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.
- package/NOTICE +9 -0
- package/README.md +207 -28
- package/SECURITY.md +92 -45
- package/dist/THIRD-PARTY-NOTICES.txt +682 -0
- package/dist/api/catalog.d.cts +69 -0
- package/dist/api/catalog.d.ts +50 -2
- package/dist/api/cli-options.d.cts +39 -0
- package/dist/api/cli-options.d.ts +39 -0
- package/dist/api/client.d.cts +89 -0
- package/dist/api/client.d.ts +19 -30
- package/dist/api/docs.d.cts +211 -0
- package/dist/api/docs.d.ts +211 -0
- package/dist/api/guidance.d.cts +81 -0
- package/dist/api/guidance.d.ts +81 -0
- package/dist/api/index.cjs +6610 -2247
- package/dist/api/index.d.cts +13 -0
- package/dist/api/index.d.ts +10 -7
- package/dist/api/index.js +6610 -2247
- package/dist/api/local.cjs +118 -6
- package/dist/api/local.d.cts +95 -0
- package/dist/api/local.d.ts +70 -6
- package/dist/api/local.js +104 -6
- package/dist/api/mcp.cjs +17384 -0
- package/dist/api/mcp.d.cts +108 -0
- package/dist/api/mcp.d.ts +108 -0
- package/dist/api/mcp.js +17334 -0
- package/dist/api/otlp.d.cts +65 -0
- package/dist/api/redact.d.cts +17 -0
- package/dist/api/redact.d.ts +17 -0
- package/dist/api/requests.d.cts +26 -0
- package/dist/api/requests.d.ts +14 -16
- package/dist/api/results.d.cts +16 -0
- package/dist/api/results.d.ts +2 -1
- package/dist/api/tokens.d.cts +7 -0
- package/dist/datanotes.cjs +62511 -28069
- package/dist/docs/administration/configuration.md +59 -0
- package/dist/docs/administration/docker.md +80 -0
- package/dist/docs/administration/git-sync.md +71 -0
- package/dist/docs/administration/limits.md +69 -0
- package/dist/docs/administration/run-the-service.md +219 -0
- package/dist/docs/administration/status.md +61 -0
- package/dist/docs/administration/use-with-obsidian.md +75 -0
- package/dist/docs/api/operations/add_column.md +49 -0
- package/dist/docs/api/operations/add_constraint.md +55 -0
- package/dist/docs/api/operations/adopt_rows.md +50 -0
- package/dist/docs/api/operations/align_relations.md +41 -0
- package/dist/docs/api/operations/alter_column.md +46 -0
- package/dist/docs/api/operations/alter_table.md +67 -0
- package/dist/docs/api/operations/batch.md +48 -0
- package/dist/docs/api/operations/changes_stream.md +28 -0
- package/dist/docs/api/operations/check_table.md +29 -0
- package/dist/docs/api/operations/clone_table.md +48 -0
- package/dist/docs/api/operations/comment_on.md +42 -0
- package/dist/docs/api/operations/configure_database.md +52 -0
- package/dist/docs/api/operations/create_table.md +78 -0
- package/dist/docs/api/operations/create_view.md +54 -0
- package/dist/docs/api/operations/create_webhook.md +37 -0
- package/dist/docs/api/operations/define_base.md +52 -0
- package/dist/docs/api/operations/delete_rows.md +43 -0
- package/dist/docs/api/operations/delete_webhook.md +31 -0
- package/dist/docs/api/operations/describe_database.md +30 -0
- package/dist/docs/api/operations/describe_history.md +40 -0
- package/dist/docs/api/operations/describe_semantic_index.md +24 -0
- package/dist/docs/api/operations/describe_table.md +38 -0
- package/dist/docs/api/operations/docs.md +13 -0
- package/dist/docs/api/operations/drop_column.md +41 -0
- package/dist/docs/api/operations/drop_constraint.md +39 -0
- package/dist/docs/api/operations/drop_table.md +43 -0
- package/dist/docs/api/operations/drop_view.md +38 -0
- package/dist/docs/api/operations/engine_status.md +23 -0
- package/dist/docs/api/operations/graph_neighbors.md +32 -0
- package/dist/docs/api/operations/graph_path.md +32 -0
- package/dist/docs/api/operations/graph_traverse.md +43 -0
- package/dist/docs/api/operations/identify_session.md +24 -0
- package/dist/docs/api/operations/infer_table.md +43 -0
- package/dist/docs/api/operations/insert_row.md +48 -0
- package/dist/docs/api/operations/list_changes.md +35 -0
- package/dist/docs/api/operations/list_folder.md +28 -0
- package/dist/docs/api/operations/list_link_targets.md +44 -0
- package/dist/docs/api/operations/list_migrations.md +35 -0
- package/dist/docs/api/operations/list_tables.md +32 -0
- package/dist/docs/api/operations/list_webhooks.md +23 -0
- package/dist/docs/api/operations/manual_index.md +14 -0
- package/dist/docs/api/operations/manual_page.md +22 -0
- package/dist/docs/api/operations/merge_rows.md +44 -0
- package/dist/docs/api/operations/move_rows.md +52 -0
- package/dist/docs/api/operations/openapi.md +13 -0
- package/dist/docs/api/operations/openapi_post.md +20 -0
- package/dist/docs/api/operations/read_note.md +29 -0
- package/dist/docs/api/operations/recompute_columns.md +44 -0
- package/dist/docs/api/operations/record_tool_call.md +36 -0
- package/dist/docs/api/operations/rename_column.md +44 -0
- package/dist/docs/api/operations/rename_value.md +45 -0
- package/dist/docs/api/operations/restore_database.md +51 -0
- package/dist/docs/api/operations/restore_table.md +46 -0
- package/dist/docs/api/operations/search_notes.md +28 -0
- package/dist/docs/api/operations/select_rows.md +61 -0
- package/dist/docs/api/operations/semantic_search.md +34 -0
- package/dist/docs/api/operations/semantic_search_docs.md +26 -0
- package/dist/docs/api/operations/set_table_bases.md +44 -0
- package/dist/docs/api/operations/status.md +13 -0
- package/dist/docs/api/operations/stop_engine.md +23 -0
- package/dist/docs/api/operations/sync_semantic_index.md +33 -0
- package/dist/docs/api/operations/table_changes.md +31 -0
- package/dist/docs/api/operations/tags/auxiliary.md +14 -0
- package/dist/docs/api/operations/tags/change-feed.md +8 -0
- package/dist/docs/api/operations/tags/history.md +17 -0
- package/dist/docs/api/operations/tags/queries.md +15 -0
- package/dist/docs/api/operations/tags/rows-dml.md +16 -0
- package/dist/docs/api/operations/tags/schema-ddl.md +22 -0
- package/dist/docs/api/operations/tags/service.md +15 -0
- package/dist/docs/api/operations/tags/tokens.md +13 -0
- package/dist/docs/api/operations/tokens_create.md +34 -0
- package/dist/docs/api/operations/tokens_delete.md +29 -0
- package/dist/docs/api/operations/tokens_list.md +21 -0
- package/dist/docs/api/operations/tokens_me.md +20 -0
- package/dist/docs/api/operations/tokens_rotate.md +29 -0
- package/dist/docs/api/operations/tokens_update.md +34 -0
- package/dist/docs/api/operations/undo_migration.md +46 -0
- package/dist/docs/api/operations/update_row.md +60 -0
- package/dist/docs/api/operations/update_rows.md +46 -0
- package/dist/docs/api/operations/vacuum_table.md +37 -0
- package/dist/docs/api.md +135 -0
- package/dist/docs/develop/build-an-app.md +320 -0
- package/dist/docs/develop/build-on-datanotes.md +138 -0
- package/dist/docs/develop/change-feed-and-webhooks.md +70 -0
- package/dist/docs/develop/client.md +116 -0
- package/dist/docs/develop/concurrency.md +153 -0
- package/dist/docs/develop/http-api.md +79 -0
- package/dist/docs/develop/telemetry.md +86 -0
- package/dist/docs/guides/agents/docs-offline.md +99 -0
- package/dist/docs/guides/agents/how-agents-use-datanotes.md +124 -0
- package/dist/docs/guides/agents/prompts.md +495 -0
- package/dist/docs/guides/agents/reading-errors.md +112 -0
- package/dist/docs/guides/data-quality/check-constraints.md +379 -0
- package/dist/docs/guides/data-quality/check-table.md +63 -0
- package/dist/docs/guides/data-quality/hand-edits.md +507 -0
- package/dist/docs/guides/data-quality/sync-between-devices.md +51 -0
- package/dist/docs/guides/data-quality/validation.md +90 -0
- package/dist/docs/guides/database-objects/bases.md +480 -0
- package/dist/docs/guides/database-objects/catalogs-and-schemas.md +897 -0
- package/dist/docs/guides/database-objects/columns.md +1332 -0
- package/dist/docs/guides/database-objects/relations.md +1454 -0
- package/dist/docs/guides/database-objects/tables.md +1404 -0
- package/dist/docs/guides/database-objects/views.md +1003 -0
- package/dist/docs/guides/history/back-up.md +195 -0
- package/dist/docs/guides/history/change-data-feed.md +247 -0
- package/dist/docs/guides/history/journal-and-undo.md +262 -0
- package/dist/docs/guides/history/restore.md +341 -0
- package/dist/docs/guides/history/table-history.md +657 -0
- package/dist/docs/guides/history/vacuum.md +35 -0
- package/dist/docs/guides/read-and-write/automatic-links.md +768 -0
- package/dist/docs/guides/read-and-write/batch.md +139 -0
- package/dist/docs/guides/read-and-write/import-notes.md +896 -0
- package/dist/docs/guides/read-and-write/joins-and-aggregates.md +251 -0
- package/dist/docs/guides/read-and-write/read-and-filter.md +536 -0
- package/dist/docs/guides/read-and-write/write-rows.md +573 -0
- package/dist/docs/guides/search/link-graph.md +146 -0
- package/dist/docs/guides/search/semantic.md +133 -0
- package/dist/docs/guides/search/text.md +142 -0
- package/dist/docs/guides/security/security-model.md +110 -0
- package/dist/docs/guides/security/tokens.md +60 -0
- package/dist/docs/guides/security/who-did-what.md +42 -0
- package/dist/docs/index.md +113 -0
- package/dist/docs/llms.txt +33 -0
- package/dist/docs/reference/cli.md +136 -0
- package/dist/docs/reference/compatibility.md +63 -0
- package/dist/docs/reference/errors.md +72 -0
- package/dist/docs/reference/glossary.md +161 -0
- package/dist/docs/reference/operations/auxiliary.md +116 -0
- package/dist/docs/reference/operations/history.md +168 -0
- package/dist/docs/reference/operations/queries.md +169 -0
- package/dist/docs/reference/operations/rows.md +185 -0
- package/dist/docs/reference/operations/schema.md +316 -0
- package/dist/docs/reference/operations.md +96 -0
- package/dist/docs/reference/settings.md +31 -0
- package/dist/docs/release-notes.md +67 -0
- package/dist/docs/start/connect-agents.md +204 -0
- package/dist/docs/start/how-it-works.md +317 -0
- package/dist/docs/start/quick-start.md +126 -0
- package/package.json +58 -14
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Use your Markdown notes as a database
|
|
2
|
+
|
|
3
|
+
> Datanotes runs your vault, a folder of Markdown notes, as typed database tables for you and your agents.
|
|
4
|
+
|
|
5
|
+
Datanotes turns the notes you already keep into typed tables that you, your programs and your agents share. The engine checks every write. Every write through the engine is journaled and can be undone.
|
|
6
|
+
|
|
7
|
+
- [Get Started](https://datanotes.dev/start/quick-start/)
|
|
8
|
+
- [Connect an Agent](https://datanotes.dev/start/connect-agents/)
|
|
9
|
+
|
|
10
|
+
## Why use Datanotes
|
|
11
|
+
|
|
12
|
+
Your notes stay plain Markdown files. The engine adds what a database gives you.
|
|
13
|
+
|
|
14
|
+
* [Tables from your notes](https://datanotes.dev/guides/database-objects/tables/)
|
|
15
|
+
|
|
16
|
+
Each note with a `table` property is a row. One file, `metastore.yaml`, defines the columns.
|
|
17
|
+
|
|
18
|
+
* [Every write checked](https://datanotes.dev/guides/data-quality/validation/)
|
|
19
|
+
|
|
20
|
+
The engine checks types, links, unique values and CHECK rules. It refuses a bad write and changes nothing.
|
|
21
|
+
|
|
22
|
+
* [All or nothing, with many clients](https://datanotes.dev/develop/concurrency/)
|
|
23
|
+
|
|
24
|
+
Agents, programs and your phone write at the same time. Each write is checked on the latest data and applies whole or not at all.
|
|
25
|
+
|
|
26
|
+
* [Joins, views and bases](https://datanotes.dev/guides/read-and-write/joins-and-aggregates/)
|
|
27
|
+
|
|
28
|
+
Filter, join and aggregate rows. Save a query as a view, and share columns through bases.
|
|
29
|
+
|
|
30
|
+
* [History, time travel and undo](https://datanotes.dev/guides/history/journal-and-undo/)
|
|
31
|
+
|
|
32
|
+
The journal records every write through the engine and who made it. Undo a write, or, with history on, read a table as it was last week.
|
|
33
|
+
|
|
34
|
+
* [Made for agents](https://datanotes.dev/start/connect-agents/)
|
|
35
|
+
|
|
36
|
+
Claude, Cursor and Codex call every operation through the Model Context Protocol (MCP). Each refusal says how to fix the call.
|
|
37
|
+
|
|
38
|
+
* [HTTP API and client](https://datanotes.dev/develop/http-api/)
|
|
39
|
+
|
|
40
|
+
Programs call the same operations over HTTP, or from JavaScript with `datanotes/client`.
|
|
41
|
+
|
|
42
|
+
* [Search by text, meaning and links](https://datanotes.dev/guides/search/text/)
|
|
43
|
+
|
|
44
|
+
Search the text of every note, find notes by meaning, and walk the links between them.
|
|
45
|
+
|
|
46
|
+
* [Git sync and store backup](https://datanotes.dev/administration/git-sync/)
|
|
47
|
+
|
|
48
|
+
The engine commits and pushes your vault with git. A private repository backs up undo and history too.
|
|
49
|
+
|
|
50
|
+
* [Edit notes by hand](https://datanotes.dev/guides/data-quality/hand-edits/)
|
|
51
|
+
|
|
52
|
+
Use Obsidian, VS Code or git. The engine checks each edit and reports what it breaks.
|
|
53
|
+
|
|
54
|
+
## What you can build
|
|
55
|
+
|
|
56
|
+
The guides build one example you can follow: a diary of classic films in the public domain.
|
|
57
|
+
|
|
58
|
+
* [A second brain for your agent](https://datanotes.dev/guides/agents/how-agents-use-datanotes/)
|
|
59
|
+
|
|
60
|
+
Tell your agent you watched Metropolis with Anna. It logs the viewing and finds it when you ask next month.
|
|
61
|
+
|
|
62
|
+
* [Databases in your notes](https://datanotes.dev/guides/database-objects/relations/)
|
|
63
|
+
|
|
64
|
+
Keep films, actors, genres and viewings as linked tables. Every row stays a note you can open and edit.
|
|
65
|
+
|
|
66
|
+
* [Apps over your vault](https://datanotes.dev/develop/build-an-app/)
|
|
67
|
+
|
|
68
|
+
Build film night, a TypeScript app that lists the films to watch and logs each viewing.
|
|
69
|
+
|
|
70
|
+
* [Several agents, one memory](https://datanotes.dev/guides/security/tokens/)
|
|
71
|
+
|
|
72
|
+
Give each agent and script its own token. The journal shows which one wrote what.
|
|
73
|
+
|
|
74
|
+
## Run it on your notes
|
|
75
|
+
|
|
76
|
+
You need Node.js 22 or newer and a folder for your database: an empty one, or a folder of notes.
|
|
77
|
+
|
|
78
|
+
1. Start the engine on your folder:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx -y datanotes serve --database your_database_folder
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Connect your agent. This command adds Datanotes to Claude Code, and [Connect your agents](https://datanotes.dev/start/connect-agents/) covers Cursor, Codex and others:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
claude mcp add datanotes -- \
|
|
88
|
+
npx -y datanotes mcp --database your_database_folder
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
3. Ask in your own words:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
Make a table of the classic films I watch, then add Nosferatu (1922).
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then read the page that fits what you want to do next:
|
|
98
|
+
|
|
99
|
+
* [Run Datanotes on your notes](https://datanotes.dev/start/quick-start/)
|
|
100
|
+
|
|
101
|
+
Create a table, add a row and see a refusal.
|
|
102
|
+
|
|
103
|
+
* [Prompts for your agent](https://datanotes.dev/guides/agents/prompts/)
|
|
104
|
+
|
|
105
|
+
Prompts to copy, with the tools they call.
|
|
106
|
+
|
|
107
|
+
* [Build on Datanotes](https://datanotes.dev/develop/build-on-datanotes/)
|
|
108
|
+
|
|
109
|
+
Programs, apps and your own MCP server.
|
|
110
|
+
|
|
111
|
+
* [How it works](https://datanotes.dev/start/how-it-works/)
|
|
112
|
+
|
|
113
|
+
Tables, rows, the journal and the store.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Datanotes
|
|
2
|
+
|
|
3
|
+
> The engine of your second brain: Markdown notes as database tables, for you and your agents.
|
|
4
|
+
|
|
5
|
+
Datanotes runs a folder of Markdown notes as typed database tables defined in `metastore.yaml`, for people, programs and AI agents. The engine (`npx datanotes serve`) exposes an HTTP API; `datanotes/client` calls it from JavaScript; agents connect through its MCP server, `npx datanotes mcp`. Every write is validated, journaled and undoable.
|
|
6
|
+
|
|
7
|
+
Every page of the site is also published as Markdown: add `.md` to its path (`https://datanotes.dev/start/quick-start.md` for `https://datanotes.dev/start/quick-start/`; the home page is `https://datanotes.dev/index.md`), or ask for the page itself with `Accept: text/markdown`.
|
|
8
|
+
|
|
9
|
+
## Documentation Sets
|
|
10
|
+
|
|
11
|
+
- [Abridged documentation](https://datanotes.dev/llms-small.txt): a compact version of the documentation for Datanotes, with non-essential content removed
|
|
12
|
+
- [Complete documentation](https://datanotes.dev/llms-full.txt): the full documentation for Datanotes
|
|
13
|
+
- [Get started](https://datanotes.dev/_llms-txt/get-started.txt): what Datanotes is, running the engine on your notes, connecting agents, and how the engine works
|
|
14
|
+
- [Database objects](https://datanotes.dev/_llms-txt/database-objects.txt): catalogs and schemas, tables, columns and types, views, bases, relations and hierarchies, with the engine's real answers
|
|
15
|
+
- [Data quality](https://datanotes.dev/_llms-txt/data-quality.txt): validation of every write, CHECK constraints, hand edits, check_table and a vault synced between devices
|
|
16
|
+
- [Read and write data](https://datanotes.dev/_llms-txt/read-and-write-data.txt): filters, joins and aggregates, writing and moving rows, automatic links, batches, importing existing notes
|
|
17
|
+
- [Search](https://datanotes.dev/_llms-txt/search.txt): reading and searching notes, semantic search, the link graph
|
|
18
|
+
- [History and recovery](https://datanotes.dev/_llms-txt/history-and-recovery.txt): the journal and undo, table history and time travel, the change data feed, restores and vacuum
|
|
19
|
+
- [Agents](https://datanotes.dev/_llms-txt/agents.txt): how an agent works with the vault, prompts with the tools they call, reading errors, the docs offline
|
|
20
|
+
- [Security](https://datanotes.dev/_llms-txt/security.txt): named tokens and permissions, who did what, the security model
|
|
21
|
+
- [Develop](https://datanotes.dev/_llms-txt/develop.txt): HTTP API, JavaScript client, concurrent writes, building an app or your own MCP server, the change feed and webhooks, telemetry
|
|
22
|
+
- [Operations reference](https://datanotes.dev/_llms-txt/operations-reference.txt): every operation of the API (also the MCP tools), by kind, with its parameters
|
|
23
|
+
- [Administration](https://datanotes.dev/_llms-txt/administration.txt): running the service, Docker, git sync, datanotes status, configuration
|
|
24
|
+
|
|
25
|
+
## Notes
|
|
26
|
+
|
|
27
|
+
- The complete documentation includes all content from the official documentation
|
|
28
|
+
- The content is automatically generated from the same source as the official documentation
|
|
29
|
+
|
|
30
|
+
## Optional
|
|
31
|
+
|
|
32
|
+
- [Connect agents](https://datanotes.dev/start/connect-agents.md): how an agent reaches the engine: the MCP server datanotes mcp, its configuration in MCP clients, and named tokens for agents
|
|
33
|
+
- [OpenAPI](https://datanotes.dev/openapi.json): OpenAPI 3.1 description of the /datanotes/* routes
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Command line
|
|
2
|
+
|
|
3
|
+
> The datanotes command and its options.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
datanotes 3.0.0: Markdown notes as database tables, for you and your agents.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
datanotes serve --database <folder> [options] run the engine and its HTTP API (/datanotes/*)
|
|
11
|
+
datanotes status --database <folder> [--json] the running engine's health
|
|
12
|
+
datanotes stop --database <folder> [--timeout-s <s>] stop the running engine gracefully
|
|
13
|
+
datanotes store path --database <folder> where the engine keeps the database's store
|
|
14
|
+
datanotes store new-id --database <folder> a new database id (a copied folder gets its own store)
|
|
15
|
+
datanotes store backup --database <folder> show or set the store's git backup (--remote <url>, --off)
|
|
16
|
+
datanotes store restore --from <url> --database <folder> restore the store from its git backup
|
|
17
|
+
Every command takes --vault <folder> instead of --database for a vault holding the database.
|
|
18
|
+
datanotes mcp --database <folder> MCP server over stdio, on the engine running on the folder
|
|
19
|
+
(or one it starts for the session)
|
|
20
|
+
datanotes mcp --url <url> --token-file <f> MCP server over stdio, on an engine at an address
|
|
21
|
+
datanotes mcp serve [options] MCP server over Streamable HTTP at /mcp (each agent sends its token)
|
|
22
|
+
datanotes --version | --help
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Options of serve:
|
|
26
|
+
--database <folder> the database folder (or DATANOTES_DATABASE): metastore.yaml at its
|
|
27
|
+
root (created there for a new database); paths start with the catalog
|
|
28
|
+
--vault <folder> or a vault holding the database (or DATANOTES_VAULT), for apps such as
|
|
29
|
+
Obsidian: the database is the folder of the vault's one metastore.yaml
|
|
30
|
+
(a new database: datanotes/); paths start at the vault's root
|
|
31
|
+
--store <folder> the engine's store (or DATANOTES_STORE; default <data home>/<database id>)
|
|
32
|
+
--settings <file> settings file (or DATANOTES_SETTINGS; default settings.json in the store)
|
|
33
|
+
--host <address> listen address (or DATANOTES_HOST; default 127.0.0.1)
|
|
34
|
+
--port <port> HTTP port for this run (or DATANOTES_PORT; default: the setting
|
|
35
|
+
httpServerPort, 27150); 0 for any free port, printed at start
|
|
36
|
+
--watch events|poll how file changes are seen (or DATANOTES_WATCH; default events)
|
|
37
|
+
--poll-ms <ms> poll interval (or DATANOTES_POLL_MS; default 3000)
|
|
38
|
+
--embedding-key-file <file> file with the API key of the embedding provider (or DATANOTES_EMBEDDING_KEY_FILE;
|
|
39
|
+
DATANOTES_EMBEDDING_KEY gives the key itself)
|
|
40
|
+
--git-sync commit, pull and push the vault (or DATANOTES_GIT_SYNC=1; --git-no-push)
|
|
41
|
+
--git-interval-min <min> minutes between two syncs (or DATANOTES_GIT_INTERVAL_MIN; default 10)
|
|
42
|
+
--git-quiet-s <s> a sync also <s> seconds after the last write (or DATANOTES_GIT_QUIET_S; default 60)
|
|
43
|
+
DATANOTES_GIT_NETWORK_TIMEOUT_S: the time limit of a pull or push (default 600)
|
|
44
|
+
--store-backup back up the store to git for this run (or DATANOTES_STORE_BACKUP=1; the
|
|
45
|
+
setting storeBackupEnabled keeps it on; --no-store-backup or =0 turns it off)
|
|
46
|
+
--store-backup-remote <url> the store backup's git remote; turns the backup on
|
|
47
|
+
(or DATANOTES_STORE_BACKUP_REMOTE; default: the setting storeBackupRemote)
|
|
48
|
+
--store-backup-interval-s <s> every <s> seconds (at least 10), when the store changed: a commit
|
|
49
|
+
between two operations, then a push (or DATANOTES_STORE_BACKUP_INTERVAL_S;
|
|
50
|
+
default: the setting storeBackupIntervalSeconds, 60)
|
|
51
|
+
--log <file> append console output to a file
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Options of status (the engine is found through the lock in its store, called with the owner's token):
|
|
55
|
+
--database <folder> the database folder (or DATANOTES_DATABASE; --vault <folder> for a vault)
|
|
56
|
+
--store <folder> the engine's store, when serve was given one (or DATANOTES_STORE)
|
|
57
|
+
--settings <file> settings file with the owner's token (or DATANOTES_SETTINGS;
|
|
58
|
+
default settings.json in the store)
|
|
59
|
+
--url <url> --token <token> call this engine instead, e.g. on another machine (or DATANOTES_URL, DATANOTES_TOKEN)
|
|
60
|
+
--json the report as JSON
|
|
61
|
+
Exit codes: 0 healthy; 1 needs attention (git sync blocked, store backup failing, a webhook failing, change feed not
|
|
62
|
+
running, hand edits breaking the tables' rules in the last 24 h); 2 no engine running on the folder (or
|
|
63
|
+
not reachable); 3 an engine runs but its status could not be read (no owner token, token refused, an error).
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
Options of stop (the engine finishes the requests under way, makes its last git sync and store backup
|
|
67
|
+
commit and push, releases its lock and exits):
|
|
68
|
+
--database <folder> the database folder (or DATANOTES_DATABASE; --vault <folder> for a vault)
|
|
69
|
+
--store <folder> the engine's store, when serve was given one (or DATANOTES_STORE)
|
|
70
|
+
--settings <file> settings file with the owner's token (or DATANOTES_SETTINGS;
|
|
71
|
+
default settings.json in the store)
|
|
72
|
+
--url <url> --token <token> stop this engine instead (or DATANOTES_URL, DATANOTES_TOKEN)
|
|
73
|
+
--timeout-s <seconds> how long to wait for the engine to exit (default 60)
|
|
74
|
+
--json the report as JSON
|
|
75
|
+
Exit codes: 0 stopped; 1 not stopped (not answering, or still running after the timeout: stop it by
|
|
76
|
+
force); 2 no engine running on the folder; 3 the stop could not be asked (another machine, still
|
|
77
|
+
starting, token refused).
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
Options of store:
|
|
81
|
+
--database <folder> the database folder (or DATANOTES_DATABASE; --vault <folder> for a vault)
|
|
82
|
+
--json store path, store backup: the answer as JSON
|
|
83
|
+
--remote <url> store backup: turn it on, pushing to this git repository (a first push now)
|
|
84
|
+
--ssh-command <cmd> store backup, with --remote: the store repository's core.sshCommand
|
|
85
|
+
(default: the vault repository's), e.g. C:/Windows/System32/OpenSSH/ssh.exe
|
|
86
|
+
--interval-s <seconds> store backup: every <seconds> (at least 10, default 60), when the
|
|
87
|
+
store changed: a commit between two operations, then a push
|
|
88
|
+
--off store backup: turn it off (the store's repository stays)
|
|
89
|
+
--from <url> store restore: the git repository of the store backup
|
|
90
|
+
--port <port> store restore: the HTTP port in the new settings (default 27150)
|
|
91
|
+
--force store restore: restore over a store that exists (kept aside, renamed)
|
|
92
|
+
--no-backup store restore: leave the store backup off in the new settings
|
|
93
|
+
backup and restore change the store only while no engine runs on the database.
|
|
94
|
+
The data home holds one store per database: %LOCALAPPDATA%\Datanotes (Windows),
|
|
95
|
+
~/Library/Application Support/Datanotes (macOS), $XDG_DATA_HOME/datanotes or
|
|
96
|
+
~/.local/share/datanotes (Linux); DATANOTES_DATA_HOME moves it.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
Options of mcp (stdio):
|
|
100
|
+
--database <folder> the database folder (or DATANOTES_DATABASE); acts with the owner's token,
|
|
101
|
+
and stops the engine it started when the client closes
|
|
102
|
+
--vault <folder> or a vault holding the database (or DATANOTES_VAULT)
|
|
103
|
+
--url <url> the engine's address (or DATANOTES_URL), with
|
|
104
|
+
--token-file <file> a file holding the token (or DATANOTES_TOKEN_FILE, or the token in DATANOTES_TOKEN)
|
|
105
|
+
DATANOTES_ENGINE_START_TIMEOUT_S: how long --database waits for the engine
|
|
106
|
+
it starts, in seconds (default 60; a large database starts slowly)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
Options of mcp serve:
|
|
110
|
+
--url <url> the engine (default http://127.0.0.1:27150, or DATANOTES_URL)
|
|
111
|
+
--host <address> listen address (default 127.0.0.1, or DATANOTES_MCP_HOST)
|
|
112
|
+
--port <n> port (default 27151, or DATANOTES_MCP_PORT)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
Tools of mcp (both modes; default: every tool except create_webhook and delete_webhook):
|
|
116
|
+
--profile <name> read (read-only tools), write (no schema changes, no webhooks) or
|
|
117
|
+
all (every tool, webhooks included) (or DATANOTES_MCP_PROFILE)
|
|
118
|
+
--tools <names> only these tools, separated by commas (or DATANOTES_MCP_TOOLS)
|
|
119
|
+
--except <names> none of these tools, separated by commas (or DATANOTES_MCP_EXCEPT)
|
|
120
|
+
--owner-tools also offer create_webhook and delete_webhook
|
|
121
|
+
(or DATANOTES_MCP_OWNER_TOOLS=1)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
Logs of mcp (both modes):
|
|
125
|
+
--otlp-endpoint <url> export logs over OTLP/HTTP, e.g. http://127.0.0.1:4318 (or the standard
|
|
126
|
+
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_SERVICE_NAME)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Docs of mcp (both modes): the tools list_docs, read_docs and search_docs read the docs of this
|
|
130
|
+
version from the package (dist/docs), or from the folder in DATANOTES_DOCS_DIR; search_docs also
|
|
131
|
+
ranks them by meaning when the engine has semantic search on (hybrid search)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
Agents connect through the MCP server: npx -y datanotes mcp (https://datanotes.dev/start/connect-agents/).
|
|
135
|
+
Docs: https://datanotes.dev
|
|
136
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Compatibility
|
|
2
|
+
|
|
3
|
+
> What Datanotes 3 promises: every 3.x version adds to what you use and never takes it away.
|
|
4
|
+
|
|
5
|
+
Datanotes 3 keeps working with your programs, scripts and vaults in every 3.x version. The number after the 3 only says how recent a release is: 3.1, 3.2, and on.
|
|
6
|
+
|
|
7
|
+
## The promise
|
|
8
|
+
|
|
9
|
+
What works in Datanotes 3 keeps working the same way in every 3.x version:
|
|
10
|
+
|
|
11
|
+
* Operations, their arguments and their answer fields
|
|
12
|
+
* HTTP routes and headers
|
|
13
|
+
* Violation codes
|
|
14
|
+
* Commands, their options and their exit codes
|
|
15
|
+
* Environment variables and settings
|
|
16
|
+
* The words of `metastore.yaml`
|
|
17
|
+
|
|
18
|
+
A new version can add to these. It never removes or renames them, and a name never changes meaning. When Datanotes needs a different behavior, it adds a new name. The old name keeps doing what it did.
|
|
19
|
+
|
|
20
|
+
For example, a program that calls `insert_row` with `table` and `values`, then reads `planned_creates`, works with every 3.x version. A later version can add an optional argument, a new answer field or a new operation, and the program doesn’t notice.
|
|
21
|
+
|
|
22
|
+
These cases fall outside the promise:
|
|
23
|
+
|
|
24
|
+
* **Security fixes**: a fix can change a behavior. The release notes say so.
|
|
25
|
+
* **Bugs**: Datanotes fixes behavior that contradicts the documentation.
|
|
26
|
+
* **Undocumented behavior**: only what the docs describe is covered.
|
|
27
|
+
* **Messages**: the text of refusals and hints can improve in any version.
|
|
28
|
+
* **Node.js versions**: support follows the Node.js long-term support releases.
|
|
29
|
+
|
|
30
|
+
## Write tolerant clients
|
|
31
|
+
|
|
32
|
+
Answers can gain fields, and enums can gain values. Write your client to accept them:
|
|
33
|
+
|
|
34
|
+
* Ignore fields you don’t know.
|
|
35
|
+
* Handle an enum value you don’t know, for example as “other”.
|
|
36
|
+
* Read refusals by their HTTP status, not by their text.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { DatanotesClient } from "datanotes/client";
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const db = new DatanotesClient({
|
|
43
|
+
url: "http://127.0.0.1:27150",
|
|
44
|
+
token: process.env.DATANOTES_TOKEN ?? "",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
type Created = { planned_creates: string[] };
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const r = await db.call("insert_row", {
|
|
52
|
+
table: "film",
|
|
53
|
+
values: { title: "Metropolis" },
|
|
54
|
+
});
|
|
55
|
+
// read the fields you need: new ones may appear
|
|
56
|
+
if (r.ok) console.log((r.value as Created).planned_creates);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## How Datanotes keeps it
|
|
60
|
+
|
|
61
|
+
The repository keeps the whole public contract in `contract/datanotes-3.txt`. It has one line for every operation, argument, answer field, route, command option, environment variable, setting and violation code.
|
|
62
|
+
|
|
63
|
+
The test suite fails when a line goes or changes, so a machine checks the promise. A second test checks every new name against the naming rules before it ships.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Errors
|
|
2
|
+
|
|
3
|
+
> Every kind of error the engine and the MCP server answer, with its status, what its hint gives and the page its docs link names.
|
|
4
|
+
|
|
5
|
+
Every error of the engine says three things: what is wrong (`error`), how to fix it (`hint`) and where to read more (`docs`, a page of this site in Markdown, with its anchor). The HTTP API sends them as JSON fields; the MCP server and `DatanotesError` end the text with a `Hint:` and a `Docs:` line. The docs line of `DatanotesError` gives the address, then the `read_docs` call that reads the same section offline; `datanotes mcp` gives only the call:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
insert_row refused — nothing was written:
|
|
9
|
+
invalid datanotes/main/public/film/Sunrise.md: status must be one of: to watch; watched
|
|
10
|
+
Hint: Use one of the allowed values listed in the message, written exactly; describe_table shows what each one means. To add a value, alter_column the enum.
|
|
11
|
+
Docs: https://datanotes.dev/guides/database-objects/columns.md#describe-what-each-enum-value-means (offline: read_docs("guides/database-objects/columns#describe-what-each-enum-value-means"))
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
[Read the engine’s errors](https://datanotes.dev/guides/agents/reading-errors/) shows how an agent uses them.
|
|
15
|
+
|
|
16
|
+
## Kinds of error
|
|
17
|
+
|
|
18
|
+
| Error | Status | The hint gives | Docs |
|
|
19
|
+
| ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| Unknown tool or operation | MCP tool error; 400 | The closest tools | [Operations](https://datanotes.dev/reference/operations/) |
|
|
21
|
+
| Argument unknown, missing or of the wrong type | MCP tool error, before the call | The argument meant, and the tool’s arguments with their types | The operation’s reference |
|
|
22
|
+
| Bad input to an operation or a route | 400 | Its own where the answer is data, else the operation’s arguments | The topic’s page, or the operation’s reference |
|
|
23
|
+
| Table or view not found | 404 | The closest names and aliases, the tables and views, or the view’s table where a table is needed | [Find the table that matches a request](https://datanotes.dev/guides/database-objects/tables/#find-the-table-that-matches-a-request), [Store a query as a view](https://datanotes.dev/guides/database-objects/views/#store-a-query-as-a-view) |
|
|
24
|
+
| Ambiguous table name | 409 | The full names | [Place tables in catalogs and schemas](https://datanotes.dev/guides/database-objects/catalogs-and-schemas/#place-tables-in-catalogs-and-schemas) |
|
|
25
|
+
| Unknown column | 400 | The closest column, the table’s columns, `describe_table` and `add_column` | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
26
|
+
| Unknown filter operator | 400 | The operator meant, every operator, and the shape of a condition | [Compare values with operators](https://datanotes.dev/guides/read-and-write/read-and-filter/#compare-values-with-operators) |
|
|
27
|
+
| Bad expression or aggregate | 400 | The columns and the shape | [Group rows and compute totals](https://datanotes.dev/guides/read-and-write/joins-and-aggregates/#group-rows-and-compute-totals) |
|
|
28
|
+
| Unknown base, constraint, catalog, schema, enum value or link column | 400 | The closest name, the list, and the operation that lists them | The topic’s page |
|
|
29
|
+
| A name that isn’t an identifier | 400 | The name it could be | [Place tables in catalogs and schemas](https://datanotes.dev/guides/database-objects/catalogs-and-schemas/#place-tables-in-catalogs-and-schemas) |
|
|
30
|
+
| A table, base or column without a description, or one removed | 400 | Every missing description, and the call’s shape with each in place | [Describe every table and column](https://datanotes.dev/guides/database-objects/tables/#describe-every-table-and-column) |
|
|
31
|
+
| Row not found | 400 | The closest note name, and how to find a row’s `path` or `id` | [Update one row](https://datanotes.dev/guides/read-and-write/write-rows/#update-one-row) |
|
|
32
|
+
| A value breaks a rule (a violation) | 422 | The hint of its kind: [Violations](#violations) | The page of its kind |
|
|
33
|
+
| A conflict: `expect`, linked rows, rows that break a new CHECK, a column others read, `cascade`, a name taken, merge keys | 422 | What the conflict means and what to do | [Guard a write against concurrent edits with `expect`](https://datanotes.dev/guides/read-and-write/write-rows/#guard-a-write-against-concurrent-edits-with-expect), [Delete a row that other notes link to](https://datanotes.dev/guides/database-objects/relations/#delete-a-row-that-other-notes-link-to), [Enforce rules with CHECK constraints](https://datanotes.dev/guides/data-quality/check-constraints/#enforce-rules-with-check-constraints), [Drop a table and archive its rows](https://datanotes.dev/guides/database-objects/tables/#drop-a-table-and-archive-its-rows), [Insert or update rows with `merge_rows`](https://datanotes.dev/guides/read-and-write/write-rows/#insert-or-update-rows-with-merge_rows) |
|
|
34
|
+
| A write that failed partway, rolled back by the engine | 503, with the result as the body | Free the file, then send the write again | [The engine rolls back a write it cannot finish](https://datanotes.dev/guides/history/journal-and-undo/#the-engine-rolls-back-a-write-it-cannot-finish) |
|
|
35
|
+
| A write that failed partway, and its rollback too | 500, with the result as the body | `undo_migration` | [Undo a write](https://datanotes.dev/guides/history/journal-and-undo/#undo-a-write) |
|
|
36
|
+
| Undo refused, or migration not found | 409, 404 | Undone already, the later changes, `list_migrations` | [Undo a write](https://datanotes.dev/guides/history/journal-and-undo/#undo-a-write), [Undo refuses to overwrite later changes](https://datanotes.dev/guides/history/journal-and-undo/#undo-refuses-to-overwrite-later-changes) |
|
|
37
|
+
| No history, no such version, a time before the table existed | 400 | `alter_table` with `history: "on"`, `describe_history`, `timestamp` | [Turn history on for a table](https://datanotes.dev/guides/history/table-history/#turn-history-on-for-a-table), [List the versions of a table](https://datanotes.dev/guides/history/table-history/#list-the-versions-of-a-table) |
|
|
38
|
+
| A batch with an operation refused or unknown | 422, 400 | Each operation’s own; fix it and send the whole batch again | [Group several writes with `batch`](https://datanotes.dev/guides/read-and-write/batch/#group-several-writes-with-batch) |
|
|
39
|
+
| A token beyond its permissions | 403 | The permissions, and who changes them | [Choose what a token can do](https://datanotes.dev/guides/security/tokens/#choose-what-a-token-can-do) |
|
|
40
|
+
| Token missing or wrong | 401 | Which token to send, as a bearer token | [Authenticate your requests](https://datanotes.dev/develop/http-api/#authenticate-your-requests) |
|
|
41
|
+
| Unknown operation, route, argument, method or body | 404, 400, 405 | The closest operation, route or argument, and the routes in `openapi.json` | [Call the engines routes](https://datanotes.dev/develop/http-api/#call-the-engines-routes) |
|
|
42
|
+
| Note or folder not found | 404 | Vault paths, `list_folder` and `search_notes` | [Read a note](https://datanotes.dev/guides/search/text/#read-a-note) |
|
|
43
|
+
| Change feed, webhooks or semantic search off | 400, 503 | How to turn it on | [Follow every change with the change feed](https://datanotes.dev/guides/history/change-data-feed/#follow-every-change-with-the-change-feed), [Turn on semantic search](https://datanotes.dev/guides/search/semantic/#turn-on-semantic-search) |
|
|
44
|
+
| Engine unreachable | Thrown by the client; 502 from the MCP server | Start the engine, or check its address | [How the mcp server reaches the engine](https://datanotes.dev/start/connect-agents/#how-the-mcp-server-reaches-the-engine) |
|
|
45
|
+
| The engine can’t listen: a port in use or reserved, an address of another machine | Exit code 1 of `datanotes serve` | Another `--port`, `--port 0`, or an address of this machine | [Choose the port](https://datanotes.dev/administration/run-the-service/#choose-the-port) |
|
|
46
|
+
| A request while the engine stops | 503 | Wait for the stop, then start the engine again | [Stop the engine](https://datanotes.dev/administration/run-the-service/#stop-the-engine) |
|
|
47
|
+
| Unexpected error | 500 | None: it isn’t a mistake of the caller | None |
|
|
48
|
+
|
|
49
|
+
A refused write writes nothing, so the caller can fix the call and send it again. Hand edits that break a rule aren’t errors: `check_table` and the change feed report them as violations.
|
|
50
|
+
|
|
51
|
+
## Violations
|
|
52
|
+
|
|
53
|
+
A write the engine refuses lists its violations, each with a `code`; `check_table` and the change feed report the violations of hand edits with the same codes.
|
|
54
|
+
|
|
55
|
+
| Code | Hint | Docs |
|
|
56
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
57
|
+
| `required` | Give a value to every required column; describe_table marks them (required: true) and lists an enum’s values. | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
58
|
+
| `type` | Give each value the column’s type (describe_table shows it): numbers unquoted, dates as YYYY-MM-DD, links as “\[\[Note]]”, lists as JSON arrays. | [Create a table with typed columns](https://datanotes.dev/guides/database-objects/tables/#create-a-table-with-typed-columns) |
|
|
59
|
+
| `enum` | Use one of the allowed values listed in the message, written exactly; describe_table shows what each one means. To add a value, alter_column the enum. | [Describe what each enum value means](https://datanotes.dev/guides/database-objects/columns/#describe-what-each-enum-value-means) |
|
|
60
|
+
| `vocabulary` | Use one of the values listed in the message, or first insert the new value as a row of the vocabulary table. | [Take allowed values from another table](https://datanotes.dev/guides/database-objects/relations/#take-allowed-values-from-another-table) |
|
|
61
|
+
| `min` | Give a value inside the column’s range (the message names the bound); describe_table shows its min and max. | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
62
|
+
| `max` | Give a value inside the column’s range (the message names the bound); describe_table shows its min and max. | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
63
|
+
| `step` | Give a multiple of the column’s step (describe_table shows it). | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
64
|
+
| `broken_link` | Link to a note that exists, as “\[\[Note name]]”: list_link_targets(table, column) lists the rows the column may point to. | [Point a column to a row of another table](https://datanotes.dev/guides/database-objects/relations/#point-a-column-to-a-row-of-another-table) |
|
|
65
|
+
| `ref` | Link to a row of the table the column points to (its ref) that its ref_where / ref_by allow: list_link_targets(table, column) lists them. | [Limit link targets with `ref_by` and `ref_where`](https://datanotes.dev/guides/database-objects/relations/#limit-link-targets-with-ref_by-and-ref_where) |
|
|
66
|
+
| `unique` | Another row already has this value: choose another one, or update that row instead (select_rows finds it). | [Update one row](https://datanotes.dev/guides/read-and-write/write-rows/#update-one-row) |
|
|
67
|
+
| `unknown_column` | Write only the table’s columns: describe_table lists them. To keep a new front matter key, add_column first. | [Describe a table before writing to it](https://datanotes.dev/guides/database-objects/tables/#describe-a-table-before-writing-to-it) |
|
|
68
|
+
| `check` | The row breaks a CHECK constraint of the table (named in the message, with its rule): change the values so the rule holds. describe_table lists the table’s constraints. | [Enforce rules with CHECK constraints](https://datanotes.dev/guides/data-quality/check-constraints/#enforce-rules-with-check-constraints) |
|
|
69
|
+
| `generated` | A generated column is computed by the engine: do not write it; recompute_columns sets it again. | [Recompute generated columns after a hand edit](https://datanotes.dev/guides/data-quality/hand-edits/#recompute-generated-columns-after-a-hand-edit) |
|
|
70
|
+
| `cycle` | A row cannot be its own ancestor: point the hierarchy column to a row that is not below this one. | [Build a tree of rows with a parent link](https://datanotes.dev/guides/database-objects/relations/#build-a-tree-of-rows-with-a-parent-link) |
|
|
71
|
+
| `inverse` | Both sides of a two-way link must agree: write one side, or run align_relations to repair them. | [Repair two-way links with `align_relations`](https://datanotes.dev/guides/database-objects/relations/#repair-two-way-links-with-align_relations) |
|
|
72
|
+
| `unreadable` | The note’s front matter is not valid YAML (the message quotes the parser), so every read leaves the row out: open the note and fix the YAML, such as a quote or bracket left open or a line without `key: value`. read_note shows its text. | [Find rows whose front matter can’t be read](https://datanotes.dev/guides/data-quality/hand-edits/#find-rows-whose-front-matter-cant-be-read) |
|