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.
- 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 +62911 -28409
- 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 +59 -14
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Configure the engine and the database
|
|
2
|
+
|
|
3
|
+
> The engine’s settings file in its store, the database’s own settings in metastore.yaml, and the environment variables of the datanotes commands.
|
|
4
|
+
|
|
5
|
+
Datanotes keeps its configuration in two places, for two different things:
|
|
6
|
+
|
|
7
|
+
* **The engine’s settings**: `settings.json` in the engine’s store, read when the engine starts; the port, the owner token, logs, telemetry, semantic search and the store backup
|
|
8
|
+
* **The database’s settings**: the `config` of `metastore.yaml`, in the database folder, changed while the engine runs with `configure_database`; the default catalog and schema, the time zone, the archive folder, history and automatic links
|
|
9
|
+
|
|
10
|
+
## Change the engine’s settings
|
|
11
|
+
|
|
12
|
+
The engine reads its settings file when it starts, and writes it at the first start with the port `27150` and a random owner token. Missing keys take their default. The file is in the engine’s store, outside your notes. Find it with `datanotes store path`:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx -y datanotes store path --database your_database_folder
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
To change a setting, stop the engine, edit `settings.json` in that folder and start the engine again:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"httpServerPort": 27150,
|
|
23
|
+
"httpServerToken": "your_owner_token",
|
|
24
|
+
"journalRetentionDays": 90,
|
|
25
|
+
"fileLogEnabled": true
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`datanotes store backup` writes the store backup’s settings for you: [Back up the history](https://datanotes.dev/guides/history/back-up/) shows how. The settings file itself is never backed up.
|
|
30
|
+
|
|
31
|
+
`--settings` (or `DATANOTES_SETTINGS`) names another file. The [settings reference](https://datanotes.dev/reference/settings/) lists every key and its default. The file holds the owner token, so keep it private.
|
|
32
|
+
|
|
33
|
+
The settings file doesn’t name the database folder or the store. The engine finds the database folder at start, and the store by the database’s id: [Run the engine as a service](https://datanotes.dev/administration/run-the-service/#where-the-engine-keeps-its-store) explains both, with the `--store` and `DATANOTES_DATA_HOME` options.
|
|
34
|
+
|
|
35
|
+
## Change the database’s settings
|
|
36
|
+
|
|
37
|
+
The database’s settings live in `metastore.yaml`, which changes only through operations. [`configure_database`](https://datanotes.dev/reference/operations/auxiliary/#configure_database) sets them, and returns the database as `describe_database` describes it:
|
|
38
|
+
|
|
39
|
+
* **`default_catalog`** and **`default_schema`**: where short table names, such as `film`, resolve
|
|
40
|
+
* **`root`**: the database folder in a vault; renaming it moves the folder and rewrites the links to its notes, and `""` moves the database to the vault root
|
|
41
|
+
* **`default_partition`** and **`filename`**: the sub-folders and file names of new time-based tables
|
|
42
|
+
* **`archive_folder`**: where deleted rows go
|
|
43
|
+
* **`timezone`**: the IANA time zone that completes date-times written without an offset
|
|
44
|
+
* **`history`**: the transaction log for every table; `true` in a database the engine creates, and off when `config` lacks it. See [The transaction log keeps every version](https://datanotes.dev/start/how-it-works/#the-transaction-log-keeps-every-version) for its disk cost
|
|
45
|
+
* **`autolink`**: [automatic links](https://datanotes.dev/guides/read-and-write/automatic-links/) in the text writes put in notes, on by default
|
|
46
|
+
|
|
47
|
+
To revert a change, call `configure_database` again with the previous values. A move of the database folder with `root` is recorded in the journal and in the history of every table, so undo and time travel find the rows in their new folder. [Configure the database settings](https://datanotes.dev/guides/database-objects/catalogs-and-schemas/#configure-the-database-settings) shows it on a real engine.
|
|
48
|
+
|
|
49
|
+
`metastore.yaml` also holds the database’s `id`, at the top. The engine writes it and finds the database’s store by it, so leave it as it is.
|
|
50
|
+
|
|
51
|
+
## Set options with environment variables
|
|
52
|
+
|
|
53
|
+
Every option of the `datanotes` commands also has an environment variable, which applies when the command line doesn’t give the option. They suit containers and services:
|
|
54
|
+
|
|
55
|
+
* **`datanotes serve`**: [Run the engine as a service](https://datanotes.dev/administration/run-the-service/#set-the-options-of-serve), [Sync the vault with git](https://datanotes.dev/administration/git-sync/) and [Back up the history](https://datanotes.dev/guides/history/back-up/#set-the-backup-for-one-run)
|
|
56
|
+
* **`datanotes mcp`**: [Connect your agents](https://datanotes.dev/start/connect-agents/#set-options-with-flags-or-environment-variables)
|
|
57
|
+
* **Telemetry**: the `OTEL_EXPORTER_OTLP_*` variables, in [Send logs to your observability backend](https://datanotes.dev/develop/telemetry/)
|
|
58
|
+
|
|
59
|
+
The [command line reference](https://datanotes.dev/reference/cli/) shows every command and option.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Run in Docker
|
|
2
|
+
|
|
3
|
+
> The engine in a container, on a server.
|
|
4
|
+
|
|
5
|
+
You can run the headless engine (`src/node/service.ts`) in a container, on any machine that runs Docker, such as a virtual private server (VPS), a network-attached storage (NAS) device or a Linux server. This page shows how to:
|
|
6
|
+
|
|
7
|
+
* Start the engine and find its token
|
|
8
|
+
* Set up file watching and permissions
|
|
9
|
+
* Open network access and connect agents
|
|
10
|
+
|
|
11
|
+
## Start the engine
|
|
12
|
+
|
|
13
|
+
Build the engine first, then start the container with Docker Compose:
|
|
14
|
+
|
|
15
|
+
1. Build the service from the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run build:service
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. Start the container on your vault folder:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
DATANOTES_VAULT=your_vault_folder docker compose \
|
|
25
|
+
-f deploy/docker/docker-compose.yml up -d --build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The container mounts your vault folder at `/vault`, and its entrypoint starts the engine with `--vault /vault`. The database is then a folder inside the vault, `datanotes/` for a new database. A folder that holds `metastore.yaml` at its root works too: the engine then finds the database at the vault root. [Use Datanotes with Obsidian](https://datanotes.dev/administration/use-with-obsidian/) explains both setups. The first start creates the settings file, `/config/settings.json`, in the `datanotes-config` volume, with port 27150 and a random owner token. The [settings reference](https://datanotes.dev/reference/settings/) lists every key you can set there, such as semantic search and logs.
|
|
29
|
+
|
|
30
|
+
## Keep the engine’s store in a volume
|
|
31
|
+
|
|
32
|
+
The engine keeps its store outside the vault: the journal, the history of your tables, the named tokens, the change feed and the logs. In the container, the store is `/data/<database id>/`, in the `datanotes-data` volume. The image sets `DATANOTES_DATA_HOME=/data`. Keep that volume: without it, a new container starts with an empty journal and no history.
|
|
33
|
+
|
|
34
|
+
## Get the owner token
|
|
35
|
+
|
|
36
|
+
The owner token is in the settings file inside the container. Print it with:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
docker compose -f deploy/docker/docker-compose.yml \
|
|
40
|
+
exec datanotes cat /config/settings.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The owner token gives full access. Keep it for administration, and [create a named token](https://datanotes.dev/guides/security/tokens/#create-a-token) for each agent, program or device.
|
|
44
|
+
|
|
45
|
+
## Run programs next to the engine
|
|
46
|
+
|
|
47
|
+
Programs such as a task planner or your own agent run as their own containers or processes. Each one gets its own token from `POST /datanotes/tokens/create/` and reaches the engine over HTTP. [Build on Datanotes](https://datanotes.dev/develop/build-on-datanotes/) explains the ways to build on the engine.
|
|
48
|
+
|
|
49
|
+
## Choose how the engine sees file changes
|
|
50
|
+
|
|
51
|
+
The container polls the vault for changes every 3s, because `DATANOTES_WATCH` defaults to `poll`. Bind mounts from Windows and macOS hosts deliver no file events, so polling is the only option there. On a Linux host, set `DATANOTES_WATCH=events` to react to changes as they happen.
|
|
52
|
+
|
|
53
|
+
Polling a large vault over a bind mount is slow: one scan of 10,000 notes takes seconds. The engine then scans less often, so a change you make on the host shows later. On Windows and macOS, keep a large vault on a Linux volume instead, and set `DATANOTES_WATCH=events`. [Limits](https://datanotes.dev/administration/limits/#keep-a-docker-vault-on-a-linux-volume) shows the compose file and the times we measured.
|
|
54
|
+
|
|
55
|
+
## Run one engine per vault
|
|
56
|
+
|
|
57
|
+
Run one engine per database folder. The engine holds a lock file, `engine.lock`, in its store, so it refuses only a second engine with the same store. The container keeps its store in its own volume. An engine on the host has another store, so it starts on the same folder, and the two engines lose each other’s writes.
|
|
58
|
+
|
|
59
|
+
Never run the engine on the host and the engine in Docker on the same folder. Stop the host engine with `datanotes stop` before you start the container. [Sync the vault between devices](https://datanotes.dev/guides/data-quality/sync-between-devices/) explains the same rule for a synced vault.
|
|
60
|
+
|
|
61
|
+
## Give the container write access to the vault
|
|
62
|
+
|
|
63
|
+
The container runs as the user `engine`, and the engine writes notes in the vault. On its first start it also writes the database’s id into `metastore.yaml`. Make the vault folder writable by that user in one of two ways:
|
|
64
|
+
|
|
65
|
+
* Add a `user:` entry to the compose file with the owner of the folder
|
|
66
|
+
* Change the folder’s owner with `chown`
|
|
67
|
+
|
|
68
|
+
## Reach the engine from other machines
|
|
69
|
+
|
|
70
|
+
The compose file publishes the port on `127.0.0.1` only. To reach the engine from outside, put a reverse proxy or a tunnel in front of it. The [security page](https://datanotes.dev/guides/security/security-model/) explains what to expose and which tokens to use.
|
|
71
|
+
|
|
72
|
+
## Connect agents to the engine in Docker
|
|
73
|
+
|
|
74
|
+
Agents reach the engine through the Model Context Protocol (MCP) server. Run it next to the engine:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx -y datanotes mcp serve --url http://127.0.0.1:27150
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
[Connect agents](https://datanotes.dev/start/connect-agents/) explains how to point your agents at it.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Sync the vault with git
|
|
2
|
+
|
|
3
|
+
> Have the engine commit, pull and push the vault’s git repository, as a backup and to keep copies on other machines in step.
|
|
4
|
+
|
|
5
|
+
Git sync keeps the vault’s own git repository committed and pushed while the engine runs. Use it as a backup, and to keep a copy of the vault on another machine, such as a server, in step with this one. Git only carries the files: undo and history stay in the engine’s journal and transaction log.
|
|
6
|
+
|
|
7
|
+
## Turn on git sync
|
|
8
|
+
|
|
9
|
+
The vault must be a git repository whose branch has an upstream: push it once with `git push -u`. Start the engine with `--git-sync`:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx -y datanotes serve --database your_database_folder --git-sync
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Git runs as the user that runs the engine, with that user’s identity and SSH keys. These options turn it on and tune it:
|
|
16
|
+
|
|
17
|
+
| Option | Variable | Meaning |
|
|
18
|
+
| ----------------------- | ---------------------------- | --------------------------------------------------------------------------- |
|
|
19
|
+
| `--git-sync` | `DATANOTES_GIT_SYNC=1` | Turns git sync on |
|
|
20
|
+
| `--git-interval-min 10` | `DATANOTES_GIT_INTERVAL_MIN` | Minutes between two syncs; at least 1, default 10 |
|
|
21
|
+
| `--git-quiet-s 60` | `DATANOTES_GIT_QUIET_S` | Seconds after the engine’s last write before a sync; at least 5, default 60 |
|
|
22
|
+
| `--git-no-push` | None | Commits and pulls, but never pushes |
|
|
23
|
+
|
|
24
|
+
## What a sync does
|
|
25
|
+
|
|
26
|
+
A sync runs every `--git-interval-min` minutes, and `--git-quiet-s` seconds after the engine’s last write, so a burst of writes becomes one commit:
|
|
27
|
+
|
|
28
|
+
1. It commits the vault’s changes, with a message that lists the operations applied since the last commit and who made them.
|
|
29
|
+
2. It fetches, and when the remote has new commits, pulls them with `git pull --rebase --autostash`.
|
|
30
|
+
3. It pushes when the vault is ahead of the remote.
|
|
31
|
+
|
|
32
|
+
The commit leaves out `.obsidian/` and `.trash/`. The engine’s store, with the journal and the history of this machine, is outside the vault, so git never sees it. When the engine stops, it makes a last commit and push.
|
|
33
|
+
|
|
34
|
+
The commit also leaves out these engine files, whatever `.gitignore` says:
|
|
35
|
+
|
|
36
|
+
* **`.datanotes/`**: the store of a Datanotes 2 vault, with the owner token. The engine logs a warning when the vault still holds one. Add `.datanotes/` to `.gitignore`, or move the folder out of the vault. If an earlier commit holds it, run `git rm -r --cached .datanotes`, commit, and change the token.
|
|
37
|
+
* **`.datanotes-*.tmp`** and **`.datanotes-rename-*`**: files the engine is still writing or renaming.
|
|
38
|
+
|
|
39
|
+
Git runs from its folder on `PATH`, never from the vault folder. A `git.exe` inside the vault never runs.
|
|
40
|
+
|
|
41
|
+
## Git never waits for a person
|
|
42
|
+
|
|
43
|
+
The engine runs as a service, with nobody to answer a prompt. So git never asks:
|
|
44
|
+
|
|
45
|
+
* **No password prompt**: a missing credential fails the command at once.
|
|
46
|
+
* **No Git Credential Manager window**: the engine sets `GCM_INTERACTIVE=never`.
|
|
47
|
+
* **SSH in batch mode**: an unknown host key or a key with a passphrase fails the command. Your own `GIT_SSH_COMMAND` or `core.sshCommand` wins.
|
|
48
|
+
|
|
49
|
+
Each git command also has a time limit. A fetch, pull or push may take 10 minutes, any other command 60 seconds. Past it, the engine stops git and the processes it started. The sync then fails, `datanotes status` shows why, and the next sync tries again. Set `DATANOTES_GIT_NETWORK_TIMEOUT_S` to change the limit of a fetch, pull or push, in seconds.
|
|
50
|
+
|
|
51
|
+
Check once, as the user that runs the engine, that `git push` works without a prompt. For SSH, add the host to `known_hosts` and load the key in an SSH agent, or use a key without a passphrase.
|
|
52
|
+
|
|
53
|
+
## Back up the store too
|
|
54
|
+
|
|
55
|
+
Undo, table history and time travel read the store, not the vault. To keep them with the vault, turn on the store backup: it pushes the store to a repository of its own. It commits every 60 seconds by default, between two operations, so a restore finds both repositories at nearly the same moment. [Back up the history](https://datanotes.dev/guides/history/back-up/) shows how.
|
|
56
|
+
|
|
57
|
+
## Resolve a conflict
|
|
58
|
+
|
|
59
|
+
When a pull conflicts with local changes, the engine aborts the rebase and stops pushing, so nothing is lost. `datanotes status` then reports git sync as `blocked`, with the reason, and exits with code 1. Resolve the conflict in the repository with git, as you would for any repository; the next sync commits and pushes again.
|
|
60
|
+
|
|
61
|
+
A pull can also succeed and still leave files in conflict. This happens when the engine writes a note while the pull runs: git puts that change back after the pull, and it conflicts. The engine then stops the sync before pushing, and never commits the conflict markers. The status names the files. To resolve them:
|
|
62
|
+
|
|
63
|
+
1. Edit each file named in the status, and keep the text you want.
|
|
64
|
+
2. Run `git add` on each file.
|
|
65
|
+
3. Run `git stash drop` when git says your changes are safe in the stash.
|
|
66
|
+
|
|
67
|
+
The next sync commits and pushes again.
|
|
68
|
+
|
|
69
|
+
## Keep every copy on the same version
|
|
70
|
+
|
|
71
|
+
Each copy of the vault that runs an engine reads the notes that git brings in as hand edits: the engine checks them against the tables’ rules and reports what they break on the change feed. Run the same version of Datanotes on every copy, and upgrade them together. The [release notes](https://datanotes.dev/release-notes/) list what each version changes.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Limits
|
|
2
|
+
|
|
3
|
+
> How the engine performs on large databases: start time, select and insert times, memory, and how to run it on 10,000 notes or more.
|
|
4
|
+
|
|
5
|
+
The engine keeps every row in a Markdown note, so its speed depends on the number of notes and on the disk that holds them. This page gives the times we measured and shows how to run the engine on a large database.
|
|
6
|
+
|
|
7
|
+
## Measured times
|
|
8
|
+
|
|
9
|
+
We measured the engine on databases of 10,000 and 50,000 notes. On Windows 11, Microsoft Defender scanned the files. On Linux, the engine ran in a container with the notes on a Linux volume.
|
|
10
|
+
|
|
11
|
+
| Measure | 10,000 notes | 50,000 notes |
|
|
12
|
+
| --------------------------------------- | ------------ | ------------ |
|
|
13
|
+
| Start, Windows 11 with Defender | 15 to 18 s | 63 to 115 s |
|
|
14
|
+
| Start, Linux container | 4 to 5 s | 22 s |
|
|
15
|
+
| `select_rows` with `where` | 30 to 35 ms | 178 ms |
|
|
16
|
+
| `insert_row` | 91 to 128 ms | 414 ms |
|
|
17
|
+
| Memory (resident set size) after writes | Not measured | Up to 2 GB |
|
|
18
|
+
|
|
19
|
+
These numbers set the size the engine handles well:
|
|
20
|
+
|
|
21
|
+
* Up to about 10,000 notes, it starts within 20 seconds and answers within a few hundred milliseconds
|
|
22
|
+
* From 10,000 to 20,000 notes, start it before your agents and keep it running
|
|
23
|
+
* Above about 20,000 notes, run it as a service on Linux, and give it 2 GB of memory
|
|
24
|
+
|
|
25
|
+
## Start the engine before the agent
|
|
26
|
+
|
|
27
|
+
`datanotes mcp --database` starts an engine when none runs on the folder. The agent then waits for the whole start, up to 60 seconds. On a large database, the start can take longer than the agent waits.
|
|
28
|
+
|
|
29
|
+
Above about 20,000 notes, run `datanotes serve` as a service that starts with the machine. [Run the engine as a service](https://datanotes.dev/administration/run-the-service/) shows how. `datanotes mcp --database` then finds the running engine and connects at once.
|
|
30
|
+
|
|
31
|
+
To let `datanotes mcp` wait longer for the engine it starts, set `DATANOTES_ENGINE_START_TIMEOUT_S` in seconds:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
DATANOTES_ENGINE_START_TIMEOUT_S=300 \
|
|
35
|
+
npx -y datanotes mcp --database your_database_folder
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Change many notes at once
|
|
39
|
+
|
|
40
|
+
A git pull, a sync tool or a find and replace can change thousands of notes outside the engine. The engine then brings their generated and identity columns up to date:
|
|
41
|
+
|
|
42
|
+
* It waits until the notes of a table stay quiet for 3 seconds.
|
|
43
|
+
* It recomputes them in one operation per table, with one entry in the journal.
|
|
44
|
+
* It skips the notes whose columns need nothing, such as notes that already hold a valid `id`.
|
|
45
|
+
* It pauses between rows, so the engine still answers requests meanwhile.
|
|
46
|
+
|
|
47
|
+
## Keep a Docker vault on a Linux volume
|
|
48
|
+
|
|
49
|
+
On Windows and macOS, a Docker bind mount of a host folder delivers no file events. The engine must then poll the vault: it compares the whole folder with what it knows, every few seconds. Over a bind mount, one comparison of 10,000 notes takes seconds.
|
|
50
|
+
|
|
51
|
+
The engine adapts to slow comparisons:
|
|
52
|
+
|
|
53
|
+
* It waits at least 4 times as long as the last comparison before the next one, up to a minute.
|
|
54
|
+
* It skips the comparison before each operation while comparisons are slow. A change you make outside then shows at the next comparison.
|
|
55
|
+
|
|
56
|
+
For a large vault, keep the notes on a Linux volume instead, and watch them with file events:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
services:
|
|
60
|
+
datanotes:
|
|
61
|
+
volumes:
|
|
62
|
+
- vault:/vault
|
|
63
|
+
environment:
|
|
64
|
+
DATANOTES_WATCH: events
|
|
65
|
+
volumes:
|
|
66
|
+
vault:
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
On a Linux host, a bind mount delivers file events: set `DATANOTES_WATCH=events` there too. [Run in Docker](https://datanotes.dev/administration/docker/) explains the container.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Run the engine as a service
|
|
2
|
+
|
|
3
|
+
> Start datanotes serve on a database folder or a vault, find its store, choose its address, its port and how it sees file changes, keep one engine per database, and stop it cleanly with datanotes stop.
|
|
4
|
+
|
|
5
|
+
The engine is one process, `datanotes serve`, that runs on one folder: a database folder or a vault. It serves the [HTTP API](https://datanotes.dev/develop/http-api/) that programs, the MCP server and other clients call. It watches the folder for hand edits, and it keeps its records in its store, a folder outside it. This page shows how to start it, configure it and stop it.
|
|
6
|
+
|
|
7
|
+
## Start the engine
|
|
8
|
+
|
|
9
|
+
You need [Node.js](https://nodejs.org) 22 or newer. Start the engine on your database folder:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx -y datanotes serve --database your_database_folder
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The folder is the database: `metastore.yaml` sits at its root, and a new database creates it there. Every path is relative to the folder, such as `main/public/film/Metropolis.md` for a row.
|
|
16
|
+
|
|
17
|
+
When an app such as Obsidian opens a whole vault, start the engine on the vault with `--vault your_vault_folder` instead. The database is then a subfolder of the vault, and paths start from the vault root. [Use Datanotes with Obsidian](https://datanotes.dev/administration/use-with-obsidian/) explains this mode. Give one of the two options: the engine refuses both together.
|
|
18
|
+
|
|
19
|
+
The first start creates the engine’s store and its settings file, `settings.json`, with the port `27150` and a random owner token. The engine then serves the HTTP API on `http://127.0.0.1:27150`. To see where the store is, run:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx -y datanotes store path --database your_database_folder
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To run the engine in a container, follow [Run in Docker](https://datanotes.dev/administration/docker/).
|
|
26
|
+
|
|
27
|
+
## Where the engine keeps its store
|
|
28
|
+
|
|
29
|
+
The store holds everything the engine writes besides your notes:
|
|
30
|
+
|
|
31
|
+
* the settings file `settings.json`, with the owner token
|
|
32
|
+
* the named tokens, the webhooks and the lock `engine.lock`
|
|
33
|
+
* the journal of operations, which [undo](https://datanotes.dev/guides/history/journal-and-undo/) reads
|
|
34
|
+
* the transaction logs of [table history](https://datanotes.dev/guides/history/table-history/)
|
|
35
|
+
* the change feed, the semantic index and the log files
|
|
36
|
+
|
|
37
|
+
Each database has its own store, named after its id: `<data home>/<database id>/`. The id is the `id` line at the top of the database’s `metastore.yaml`. The data home is the operating system’s folder for per-user application data:
|
|
38
|
+
|
|
39
|
+
| System | Data home |
|
|
40
|
+
| ------- | ----------------------------------------------------------------- |
|
|
41
|
+
| Windows | `%LOCALAPPDATA%\Datanotes` |
|
|
42
|
+
| macOS | `~/Library/Application Support/Datanotes` |
|
|
43
|
+
| Linux | `$XDG_DATA_HOME/datanotes`, by default `~/.local/share/datanotes` |
|
|
44
|
+
|
|
45
|
+
Everything the engine keeps is in that one folder, so you can back it up or archive it as a whole. The [store backup](https://datanotes.dev/guides/history/back-up/) does it for you: it pushes the journal and the history to a private git repository. Your folder holds only your notes and `metastore.yaml`: sync tools and git see no engine files.
|
|
46
|
+
|
|
47
|
+
You can place the store elsewhere:
|
|
48
|
+
|
|
49
|
+
* `DATANOTES_DATA_HOME` moves the data home, for every database
|
|
50
|
+
* `--store your_store_folder`, or `DATANOTES_STORE`, names the store of this database
|
|
51
|
+
|
|
52
|
+
A store named with `--store` isn’t recorded in the data home. Give the same `--store` to `datanotes status` and set `DATANOTES_STORE` for `datanotes mcp --database`, so they find the engine.
|
|
53
|
+
|
|
54
|
+
## Set the options of serve
|
|
55
|
+
|
|
56
|
+
Each option has an environment variable, which applies when the command line doesn’t give the option:
|
|
57
|
+
|
|
58
|
+
| Option | Variable | Meaning |
|
|
59
|
+
| ------------------------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `--database your_database_folder` | `DATANOTES_DATABASE` | The database folder the engine runs on, with `metastore.yaml` at its root |
|
|
61
|
+
| `--vault your_vault_folder` | `DATANOTES_VAULT` | The vault the engine runs on, with the database in a subfolder; instead of `--database` |
|
|
62
|
+
| `--store your_store_folder` | `DATANOTES_STORE` | The engine’s store; default `<data home>/<database id>/` |
|
|
63
|
+
| None | `DATANOTES_DATA_HOME` | The data home, the folder of every store |
|
|
64
|
+
| `--settings your_settings_file` | `DATANOTES_SETTINGS` | The settings file; default `settings.json` in the store |
|
|
65
|
+
| `--host your_address` | `DATANOTES_HOST` | The address the HTTP API listens on; default `127.0.0.1` |
|
|
66
|
+
| `--port 27150` | `DATANOTES_PORT` | The port of the HTTP API for this run, over the `httpServerPort` setting; `0` for any free port |
|
|
67
|
+
| `--watch events` or `--watch poll` | `DATANOTES_WATCH` | How the engine sees file changes; default `events` |
|
|
68
|
+
| `--poll-ms 3000` | `DATANOTES_POLL_MS` | The interval of `--watch poll`, in milliseconds; at least 200 |
|
|
69
|
+
| `--embedding-key-file your_key_file` | `DATANOTES_EMBEDDING_KEY_FILE`, or the key itself in `DATANOTES_EMBEDDING_KEY` | The API key of the embedding provider for [semantic search](https://datanotes.dev/guides/search/semantic/) |
|
|
70
|
+
| `--git-sync` | `DATANOTES_GIT_SYNC=1` | Commit, pull and push the folder: [Sync the vault with git](https://datanotes.dev/administration/git-sync/) |
|
|
71
|
+
| `--store-backup` | `DATANOTES_STORE_BACKUP=1` | Back up the store to git: [Back up the history](https://datanotes.dev/guides/history/back-up/#set-the-backup-for-one-run) |
|
|
72
|
+
| `--store-backup-remote your_url` | `DATANOTES_STORE_BACKUP_REMOTE` | The store backup’s repository |
|
|
73
|
+
| `--store-backup-interval-s 60` | `DATANOTES_STORE_BACKUP_INTERVAL_S` | Seconds between two looks for changes by the store backup, at least 10 |
|
|
74
|
+
| None | `DATANOTES_GIT_NETWORK_TIMEOUT_S` | Seconds a git fetch, pull or push of git sync and the store backup may take; default 600 |
|
|
75
|
+
| `--log your_log_file` | None | Appends the console output to a file |
|
|
76
|
+
|
|
77
|
+
The port and the owner token live in the settings file, with every other setting: [Configure the engine and the database](https://datanotes.dev/administration/configuration/) explains them.
|
|
78
|
+
|
|
79
|
+
## Choose the port
|
|
80
|
+
|
|
81
|
+
The engine listens on the port of the `httpServerPort` setting, `27150` by default. To use another port for one run, pass `--port`:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx -y datanotes serve --database your_database_folder --port 27180
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
With `--port 0`, the system picks a free port. The engine prints the port at start, writes it in its lock and reports it in `datanotes status`. Tools such as `datanotes mcp --database` read the port from the lock, so they find the engine on any port. `--port` doesn’t change the settings file.
|
|
88
|
+
|
|
89
|
+
When the port is in use, the engine waits up to 45 seconds for it, because an engine that restarts may still be closing. It prints a line while it waits. When the engine can’t listen, it exits with code 1 and says why and what to do:
|
|
90
|
+
|
|
91
|
+
* **The port is in use**: another program holds it, often another engine. Stop that program, or pass another `--port`.
|
|
92
|
+
* **The system reserves the port**: choose another port from 1024 to 65535. On Windows, `netsh interface ipv4 show excludedportrange protocol=tcp` lists the reserved ports.
|
|
93
|
+
* **The address isn’t this machine’s**: give `--host` an address of this machine, such as `127.0.0.1`.
|
|
94
|
+
|
|
95
|
+
## One database per vault
|
|
96
|
+
|
|
97
|
+
With `--database`, the folder is the database, and `metastore.yaml` sits at its root.
|
|
98
|
+
|
|
99
|
+
With `--vault`, a vault holds exactly one database: the folder of its one `metastore.yaml`. A new database goes to `datanotes/` at the top of the vault. The folder can be anywhere in the vault, also in a subfolder or at the vault root.
|
|
100
|
+
|
|
101
|
+
At each start with `--vault`, the engine looks for `metastore.yaml` in the whole vault. It skips folders whose names start with a dot, and `node_modules`. Then:
|
|
102
|
+
|
|
103
|
+
* **One `metastore.yaml`**: its folder is the database folder, whatever its name, such as `Datanotes/` or `notes/db/`. The engine doesn’t rename it.
|
|
104
|
+
* **A different folder from last time, with the same id**: you moved the database folder by hand. The engine records the move.
|
|
105
|
+
* **No `metastore.yaml`**: a new database, in `datanotes/`.
|
|
106
|
+
|
|
107
|
+
When the vault holds more than one `metastore.yaml`, at any depth, the engine refuses to start and lists them. Keep the database’s folder, then remove the extra `metastore.yaml` and start the engine again. To keep its tables, create them in the database with `create_table` and copy the rows with `insert_row`.
|
|
108
|
+
|
|
109
|
+
To rename or move the database folder, call `configure_database` with `root`, or move the folder by hand. `root: ""` moves the database to the vault root, so you can start the engine with `--database` from then on. [Move the vault or the database folder](https://datanotes.dev/start/how-it-works/#move-the-vault-or-the-database-folder) explains both.
|
|
110
|
+
|
|
111
|
+
## Run a copy of a vault
|
|
112
|
+
|
|
113
|
+
A copy of a vault holds the same database id as the original. Two databases can’t share a store, so the engine refuses to start on the copy while the original vault still exists. Give the copy its own id, with the engine stopped:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx -y datanotes store new-id --vault your_copy_folder
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The copy then gets a new, empty store at its next start: new settings, a new owner token, an empty journal and no history. To run both engines at once, start the copy with `--port 0`, or set its `httpServerPort`. To keep the original’s history in the copy, copy the original’s store too and start the copy with `--store`.
|
|
120
|
+
|
|
121
|
+
`new-id` changes `metastore.yaml`, and git or a sync tool carries that change to every copy of the vault. For a second clone of a synced vault on the same machine, start the clone with its own `--store` instead.
|
|
122
|
+
|
|
123
|
+
Moving a vault isn’t a copy. When the vault recorded in the store no longer exists, or no longer holds the database, the engine follows the vault to its new place.
|
|
124
|
+
|
|
125
|
+
## Choose how the engine sees file changes
|
|
126
|
+
|
|
127
|
+
The engine reads hand edits, from an editor, git or a sync tool, as soon as it sees them:
|
|
128
|
+
|
|
129
|
+
* **`events`**: the operating system reports each change, and the engine reacts within a fraction of a second; use it on a local disk
|
|
130
|
+
* **`poll`**: the engine scans the vault every `--poll-ms` milliseconds; use it where file events don’t arrive, such as network shares and bind mounts from Windows and macOS hosts
|
|
131
|
+
|
|
132
|
+
A scan of a large vault over a slow share takes seconds. The engine then scans less often, and doesn’t scan before each operation. [Limits](https://datanotes.dev/administration/limits/#keep-a-docker-vault-on-a-linux-volume) explains this, and how to keep a large vault on a Linux volume.
|
|
133
|
+
|
|
134
|
+
In both modes, the engine reads a note you rename or move as a rename, and [repairs the links to it](https://datanotes.dev/start/how-it-works/#the-engine-repairs-links-after-a-hand-move).
|
|
135
|
+
|
|
136
|
+
## Run one engine per database
|
|
137
|
+
|
|
138
|
+
While it runs, the engine holds a lock file, `engine.lock`, in its store, with its process, host and port. A second engine with the same store refuses to start while a running engine holds it. Tools such as `datanotes status` and `datanotes mcp --database` find the engine through the lock.
|
|
139
|
+
|
|
140
|
+
On the same machine, the engine checks the lock’s process:
|
|
141
|
+
|
|
142
|
+
* a lock left by a process that is gone doesn’t block the next start, even with a fresh heartbeat
|
|
143
|
+
* a live process holds the lock, even when it hangs: the next start refuses and changes nothing
|
|
144
|
+
* a lock written before the machine started is left over
|
|
145
|
+
|
|
146
|
+
If the refusal names a process that isn’t a Datanotes engine, delete the `engine.lock` it names and start again.
|
|
147
|
+
|
|
148
|
+
Two engines started at once on the same vault take turns. The first writes the database’s id. The second waits up to 60 seconds, then refuses because the first holds the database.
|
|
149
|
+
|
|
150
|
+
The lock lives in the store, not in the database folder. So it refuses only a second engine that uses the same store. An engine with a store of its own doesn’t see it and starts, and the two engines then lose each other’s writes. That happens in three cases:
|
|
151
|
+
|
|
152
|
+
* an engine started with another `--store` or `DATANOTES_STORE`
|
|
153
|
+
* the engine in Docker next to an engine on the host, on the same folder
|
|
154
|
+
* engines on two machines that sync the same vault
|
|
155
|
+
|
|
156
|
+
Run one engine per database folder. Never run the host engine and the Docker engine on the same folder. [Sync the vault between devices](https://datanotes.dev/guides/data-quality/sync-between-devices/) shows how to run one engine on a synced vault.
|
|
157
|
+
|
|
158
|
+
## Keep the engine local
|
|
159
|
+
|
|
160
|
+
The engine listens on `127.0.0.1` unless you start it with `--host`, and it answers no Cross-Origin Resource Sharing (CORS) preflight, so web pages can’t call it. To reach it from another device, put a reverse proxy or a tunnel in front of it, over HTTPS, as the [security model](https://datanotes.dev/guides/security/security-model/) explains, and give each device its own [named token](https://datanotes.dev/guides/security/tokens/).
|
|
161
|
+
|
|
162
|
+
## Stop the engine
|
|
163
|
+
|
|
164
|
+
Stop the engine with `datanotes stop`, from any terminal of the same machine:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npx -y datanotes stop --database your_database_folder
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The engine then stops gracefully:
|
|
171
|
+
|
|
172
|
+
1. It answers new requests with status 503, and finishes the requests under way, for up to 30 seconds.
|
|
173
|
+
2. It records the hand edits it has seen, and stops writing.
|
|
174
|
+
3. The store backup makes its last commit and push, for up to 15 seconds.
|
|
175
|
+
4. Git sync makes its last commit and push, for up to 10 seconds.
|
|
176
|
+
5. It releases the lock and exits.
|
|
177
|
+
|
|
178
|
+
The engine holds its lock until git is done, so no other engine starts on the store meanwhile. A git step that runs out of time is stopped, and the next start makes it. The whole stop fits in the 60 seconds that `datanotes stop` waits.
|
|
179
|
+
|
|
180
|
+
`datanotes stop` waits for the engine to exit, for up to 60 seconds; `--timeout-s` changes the wait. It finds the engine as [`datanotes status`](https://datanotes.dev/administration/status/) does, and calls it with the owner token. With `--url` and `--token`, it stops the engine at that address. `--json` prints the report as JSON.
|
|
181
|
+
|
|
182
|
+
The exit code says what happened:
|
|
183
|
+
|
|
184
|
+
| Code | Meaning |
|
|
185
|
+
| ---- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
186
|
+
| `0` | The engine stopped |
|
|
187
|
+
| `1` | The engine didn’t stop: it didn’t answer, or still runs after the timeout |
|
|
188
|
+
| `2` | No engine runs on the folder |
|
|
189
|
+
| `3` | The engine runs but `datanotes stop` couldn’t ask it: it runs on another machine, is still starting, or refused the request |
|
|
190
|
+
|
|
191
|
+
Ctrl+C and the `SIGINT`, `SIGTERM` and `SIGBREAK` signals stop the engine the same way. A program can call the route itself, `POST /datanotes/stop/`, with the owner token. The route takes POST only: a `GET` gets status 405 and stops nothing. A named token can’t stop the engine.
|
|
192
|
+
|
|
193
|
+
A forced stop, such as `kill -9` or `Stop-Process -Force`, has two costs:
|
|
194
|
+
|
|
195
|
+
* **Git**: it skips the last commit and push. The engine makes them at its next start.
|
|
196
|
+
* **Writes**: a write it interrupts may stay half applied. The engine writes the notes first and records the write in the journal last, so `undo_migration` can’t revert that part. Run `check_table` after the next start to find the rows it left.
|
|
197
|
+
|
|
198
|
+
So use `datanotes stop` first, with a longer `--timeout-s` when the engine is busy. Outside Windows, `kill <pid>` sends `SIGTERM`, which stops the engine gracefully too. Force the stop only as a last resort.
|
|
199
|
+
|
|
200
|
+
## Stop the engine as a Windows service
|
|
201
|
+
|
|
202
|
+
Many service wrappers on Windows stop a service by ending its process, so the engine never makes its last push. Give the service a stop script instead. The script calls `datanotes stop`, and ends the process only when the engine doesn’t exit in time. Save it as `stop-datanotes.ps1`:
|
|
203
|
+
|
|
204
|
+
```powershell
|
|
205
|
+
# Stop the engine gracefully; end its process after the timeout.
|
|
206
|
+
param(
|
|
207
|
+
[string]$Database = "C:\Notes",
|
|
208
|
+
[int]$Timeout = 60
|
|
209
|
+
)
|
|
210
|
+
$out = npx -y datanotes stop --database $Database `
|
|
211
|
+
--timeout-s $Timeout --json
|
|
212
|
+
$report = $out | Out-String | ConvertFrom-Json
|
|
213
|
+
if ($report.exit_code -eq 1 -and $report.pid) {
|
|
214
|
+
Stop-Process -Id $report.pid -Force
|
|
215
|
+
}
|
|
216
|
+
exit 0
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Set the script as the stop command of your service wrapper, and give the wrapper a stop timeout longer than `$Timeout`. Exit code 2 needs nothing more: no engine runs.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Check the engine’s status
|
|
2
|
+
|
|
3
|
+
> datanotes status and POST /datanotes/status/: the engine’s health at a glance, with exit codes for scripts and monitors.
|
|
4
|
+
|
|
5
|
+
The engine reports its health in one place: its version and uptime, the database, git sync, the store backup, the change feed, webhooks, tokens and the hand edits that break the rules. You read it from a shell with `datanotes status`, or from a program with `POST /datanotes/status/`.
|
|
6
|
+
|
|
7
|
+
## Check the status from a shell
|
|
8
|
+
|
|
9
|
+
`datanotes status` prints the engine’s health report. It finds the engine through the lock file in the engine’s store, `engine.lock`, and calls the route with the owner token from the settings file. Give it the same folder and option as `datanotes serve`, `--database` or `--vault`. For a store named with `--store`, give `--store` here too:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx datanotes status --database your_database_folder
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The report looks like this. Add `--json` to get the whole object instead:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
datanotes status: needs attention
|
|
19
|
+
engine 3.0.0, pid 8124 on nas, up 3d 4h, http://127.0.0.1:27150, watch events
|
|
20
|
+
vault /srv/vault (settings /home/me/.local/share/datanotes/01a1…/settings.json)
|
|
21
|
+
store /home/me/.local/share/datanotes/01a1…, database Datanotes (id 01a1…)
|
|
22
|
+
database datanotes/metastore.yaml: 14 tables (6 with history), 3 views
|
|
23
|
+
journal 42 operations in the last 24 h; last update_rows at 2026-10-09T08:12:03.120Z by claude-code / claude-opus-5-5
|
|
24
|
+
git sync on, repo /srv/vault, last commit 2026-10-09T08:13:10.002Z, last push 2026-10-09T08:13:12.441Z, 0 pending operations
|
|
25
|
+
backup on, every 60 s, remote git@github.com:me/vault-store.git, last commit 3f9c2a1 at 2026-10-09T08:13:00.120Z, last push 2026-10-09T08:13:01.020Z, 0 pending operations, 0 commits to push
|
|
26
|
+
changes feed running, last seq 18342
|
|
27
|
+
webhooks 2 (1 failing)
|
|
28
|
+
! wh_3fa9c1d2e4b5 hooks.example.com: 4 failed attempts, retried with backoff; last error: HTTP 502
|
|
29
|
+
tokens phone (write main.public.film); assistant (write *, ddl, maintain)
|
|
30
|
+
hand edits 3 hand edits in the last 24 h, none breaking the tables' rules
|
|
31
|
+
logs files /home/me/.local/share/datanotes/01a1…/logs
|
|
32
|
+
problems:
|
|
33
|
+
- webhook wh_3fa9c1d2e4b5 (hooks.example.com) failing: HTTP 502
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The exit code suits scripts and monitors:
|
|
37
|
+
|
|
38
|
+
* **0**: the engine is healthy
|
|
39
|
+
* **1**: something needs attention, such as git sync blocked, a failing store backup push, a failing webhook, the change feed not running, hand edits breaking the rules or a refused token
|
|
40
|
+
* **2**: no engine runs on the folder; the command then shows what the files say: the lock, stale or held by which process, the settings file and the metastore
|
|
41
|
+
* **3**: an engine runs, but its status couldn’t be read: no owner token, or the engine refused or failed the request
|
|
42
|
+
|
|
43
|
+
To check an engine on another machine, pass `--url` and `--token`.
|
|
44
|
+
|
|
45
|
+
## Read the status over HTTP
|
|
46
|
+
|
|
47
|
+
`POST /datanotes/status/` returns the same report as JSON. Only the owner token can call it: a named token gets 403, even with `maintain`. The report never contains a token or a secret. It covers:
|
|
48
|
+
|
|
49
|
+
* **Engine**: version, process ID, uptime, address, watch mode and folders
|
|
50
|
+
* **Database**: the tables, how many keep history, the operations of the last 24 hours and the latest one
|
|
51
|
+
* **Git sync**: the last commit and push, the operations waiting, and `blocked` when a conflict stops it
|
|
52
|
+
* **Store backup**: in `store_backup`, the cadence, the remote without credentials, the last commit and push, what waits, and the last error; see [Back up the history](https://datanotes.dev/guides/history/back-up/#check-the-backup)
|
|
53
|
+
* **Change feed**: whether it runs, or why not
|
|
54
|
+
* **Webhooks**: each failing one, with its URL’s host and last error
|
|
55
|
+
* **Tokens**: each named token with its permissions and when it was last used
|
|
56
|
+
* **Hand edits**: the edits of the last 24 hours that leave rows breaking the tables’ rules
|
|
57
|
+
* **Logs**: where the engine writes them
|
|
58
|
+
|
|
59
|
+
`healthy` is `false` when `problems` lists something.
|
|
60
|
+
|
|
61
|
+
The engine checks nothing again to answer: it judges hand edits by the checks the change feed ran when it recorded them. A row counts while its latest change is a hand edit that broke a rule. The next change of the row, by hand or through the engine, clears it. To check a whole table, use [`check_table`](https://datanotes.dev/reference/operations/auxiliary/#check_table).
|