Operations and MCP tools
The engine’s 50 operations. datanotes-mcp offers each one as an MCP tool of the same name (apps add their own tools after these); DatanotesClient.call(name, args) runs it from code. The route behind each one is in openapi.json, except read_note, list_directory and search_simple, which use the Local-REST-API-style routes GET /vault/… and POST /search/simple/.
Every write is validated, journaled and undoable with undo_migration.
read_note
Section titled “read_note”Read Note · read-only
Read a vault file (GET /vault/{path}). Default: the raw markdown. With as_json:
{content, frontmatter, tags, path, stat} (tags without #, from the text and the
frontmatter; stat: {ctime, mtime, size} or null). A missing file is an error.
path: vault-relative, forward slashes.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | yes | ||
as_json |
boolean | false |
list_directory
Section titled “list_directory”List Vault Directory · read-only
Direct children of a vault folder (GET /vault/{folder}/): {files: [...]}. Folders end with
/, names are sorted, dot-files are hidden. "" is the vault root. A missing folder is an
error.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | "" |
search_simple
Section titled “search_simple”Search Vault · read-only
Plain-text search (POST /search/simple/): every word of query must occur, case- and
accent-insensitive, in the note’s path or text; there are no operators. Returns up to 200
files, best first: [{filename, score, matches: [{match: {start, end}, context}]}], at most 20
matches per file. context_length: characters of context on each side (default 100, max 1000).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | yes | ||
context_length |
integer | 100 |
list_tables
Section titled “list_tables”List Tables · read-only
List every table: name, catalog, schema, qualified (personal.metrics.mood — use it
wherever a table is expected; metrics.mood or mood also work when unambiguous), path and,
when declared, description and aliases (other words for what it records). Tables are
defined in database.yaml (catalog → schema → table). Returns {tables, views}: views lists the stored views (same fields, no
path): select them like tables. system.information_schema is read with select_rows.
Call this first to find the table for what the user reports (match their words against name, description and aliases), and before creating tables or columns so you reuse existing ones instead of creating duplicates.
describe_table
Section titled “describe_table”Describe Table · read-only
Describe a table (catalog.schema.table or a shorter unambiguous name): options (path/filename patterns, archive folder, exclude folders), typed columns with
label/aliases/description, dense vs sparse flag, untyped fields, and row count.
Before adding a column (e.g. a new metric), read columns and match your concept against
name, label, aliases and description; reuse an existing column when it means the same.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes |
create_table
Section titled “create_table”Create Table · write
Create table catalog.schema.name (definition in database.yaml; rows in
<root>/<catalog>/<schema>/<name>/). Names: lowercase letters, digits, _; catalog/schema default
to the database defaults.
columns: specs like{"name": "kind", "type": "enum", "values": ["a","b"], "required": true}. Types: string, integer, number, boolean, date, datetime, enum, link, list (+items), json. Attributes: required, default ("{now}"/"{today}"), min, max, step, values,ordered(enum in order: filters/avg use the position), ref (link target, fullcatalog.schema.tableor “self”), unique, label, description, aliases,generated(e.g."date(occurred_at)","{name} {surname}"),identity(“filename” | “created”),vocabulary(allowed values = names of another table’s rows),hierarchy: true(one parent link to its own table),dense(written on every row),inverseon a link column: the column of thereftable that links back (friends↔friends,children↔parents,partner↔partner); writes keep both sides in step.time_column: rows named by that date/datetime; otherwiseoptions.filename(e.g."{name}").options:descriptionandaliases(how agents find it),filename,partition,exclude.body: markdown body of new rows (row_template). Shared columns come from bases:set_table_bases. Enum columns:valuesand, for each, its meaning invalue_descriptions({"stated": "the user said it", …}): describe_table shows them and a refused value lists them. Generated link columns:generated: "link({occurred_at:YYYY-MM-DD})"withref= the days table links each row to the row ofrefnamed by the template (its folder read from the schema; the target may not exist yet).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | ||
columns |
object[] | yes | ||
schema |
string \ | null | null |
|
catalog |
string \ | null | null |
|
time_column |
string \ | null | null |
|
options |
object \ | null | null |
|
fields |
object \ | null | null |
|
body |
string \ | null | null |
|
dry_run |
boolean | false |
drop_table
Section titled “drop_table”Drop Table · destructive write
Drop a table. Refused while it has rows unless cascade="archive", which removes the
definition from database.yaml and moves all rows to the table’s archive folder (nothing is
hard-deleted; undo restores). The transaction log is kept: restore_table can bring it back.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
cascade |
string \ | null | null |
|
dry_run |
boolean | false |
add_column
Section titled “add_column”Add Column · write
Add a typed column. Sparse by default (written only on rows that have a value — use for
metrics, e.g. {"name": "metric_mood", "type": "integer", "min": 1, "max": 5, "label": "Mood", "aliases": ["mood"], "description": "Mood of the day, 1 = bad, 5 = great"}).
dense=true adds it to every row with its default. Call describe_table first: never add
a column whose meaning an existing column (name/label/aliases/description) already covers.
Column names are permanent identifiers; only rename_column changes them.
Enum columns: values and, for each, its meaning in value_descriptions ({"stated": "the user said it", …}): describe_table shows them and a refused value lists them.
Generated link columns: generated: "link({occurred_at:YYYY-MM-DD})" with ref = the days table links each row to the row of ref named by the template (its folder read from the schema; the target may not exist yet).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
column |
object | yes | ||
dense |
boolean | false |
||
dry_run |
boolean | false |
rename_column
Section titled “rename_column”Rename Column · write
Rename a column in database.yaml and on every row. Refused if to_column is already a column
of the table; a row that has a stray to_column key with a different value is a conflict, and
nothing is written. Views and note text that mention the old name are not rewritten.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
from_column |
string | yes | ||
to_column |
string | yes | ||
dry_run |
boolean | false |
drop_column
Section titled “drop_column”Drop Column · destructive write
Remove a column from the schema and every row. Previous values are journaled; revert with
undo_migration.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
name |
string | yes | ||
dry_run |
boolean | false |
alter_column
Section titled “alter_column”Alter Column · write
Change a column’s attributes (type, min/max/step, values, required, default, label,
aliases, description, note; null removes an attribute; dense true/false). Refused with
the list of violating rows when existing values do not satisfy the new definition. A
different scale means a different column: add a new one instead of rescaling. To rename one
enum value use rename_value.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
name |
string | yes | ||
changes |
object | yes | ||
dry_run |
boolean | false |
alter_table
Section titled “alter_table”Alter Table · write
Alter a table without paths: move it (catalog, schema), rename it (name), change
partition / filename patterns, description, aliases, exclude folders, row_template
(clear_row_template=true removes it) or history (“on” | “off” | “inherit”). Rows, archive and
transaction log follow; links are updated; renamed rows keep their old name in aliases. Refused
when a row cannot fill a pattern. Use dry_run to see plannedMoves; undo with undo_migration.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
catalog |
string \ | null | null |
|
schema |
string \ | null | null |
|
name |
string \ | null | null |
|
partition |
string \ | null | null |
|
filename |
string \ | null | null |
|
description |
string \ | null | null |
|
aliases |
string[] \ | null | null |
|
history |
string \ | null | null |
|
exclude |
string[] \ | null | null |
|
row_template |
string \ | null | null |
|
clear_row_template |
boolean | false |
||
dry_run |
boolean | false |
define_base
Section titled “define_base”Define Base · write
Create or replace a base: a named set of columns (same spec as create_table) that tables
inherit, like a parent class (bases in database.yaml). Tables using it get the columns
with the same name and meaning; ref: "self" means the inheriting table (e.g. a parent
column with hierarchy: true). extends builds on other bases. Replacing a base changes
every inheriting table: rename_columns ({"old": "new"}) renames the column on their rows,
drop_columns removes it from their rows; dropping a column without listing it is refused.
All affected rows are validated before any write.
Enum columns: values and, for each, its meaning in value_descriptions ({"stated": "the user said it", …}): describe_table shows them and a refused value lists them.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | ||
columns |
object[] | yes | ||
extends |
string[] \ | null | null |
|
comment |
string \ | null | null |
|
rename_columns |
object \ | null | null |
|
drop_columns |
string[] \ | null | null |
|
dry_run |
boolean | false |
set_table_bases
Section titled “set_table_bases”Set Table Bases · write
Set the bases a table inherits from (extends, in order; [] removes them). Inherited
columns come after id and before the table’s own columns. An own column with the name of an
inherited one is replaced by the inherited definition (rows must fit it); a table may only
restyle an inherited column (label, description, aliases, note, dense) with alter_column.
Dense and generated/identity columns are filled on existing rows.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
bases |
string[] | yes | ||
dry_run |
boolean | false |
describe_database
Section titled “describe_database”Describe Database · read-only
Describe the database: its folder (root), metastore (database.yaml), configuration
(default catalog and schema, row partition and file-name formats, archive folder, time zone),
journal folder, bases (shared column sets and the tables using them), catalogs → schemas → tables (with rows counts) and views.
configure_database
Section titled “configure_database”Configure Database · write
Configure the database (persisted in database.yaml config:): root (rename the database
folder; links follow; revert by renaming back), default_catalog, default_schema,
default_partition (“” = flat) and filename (date formats for new time-based tables),
archive_folder, timezone (IANA; completes date-times written without offset), history
(transaction log for every table — only on the user’s request). Returns describe_database.
Renaming root moves the folder (links to its notes are rewritten); it is not journaled: to
revert, call it again with the old value.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
root |
string \ | null | null |
|
default_catalog |
string \ | null | null |
|
default_schema |
string \ | null | null |
|
default_partition |
string \ | null | null |
|
filename |
string \ | null | null |
|
archive_folder |
string \ | null | null |
|
timezone |
string \ | null | null |
|
history |
boolean \ | null | null |
rename_value
Section titled “rename_value”Rename Value · write
Rename one value of an enum column (e.g. high → very high) in database.yaml and every
row, keeping its position, so an ordered scale is unchanged. Note text (queries, prose) is not
rewritten. Refused if to_value already exists. Undo with undo_migration. Adding or
removing classes changes the scale: create a new table instead.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
column |
string | yes | ||
from_value |
string | yes | ||
to_value |
string | yes | ||
dry_run |
boolean | false |
insert_row
Section titled “insert_row”Insert Row · write
Insert a row (new note). Values are validated against the columns; the note path comes from
the table’s path/filename patterns (e.g. an event logged today about last night lands in
last night’s day folder when you set occurred_at to last night). body is the note text.
Generated / identity columns are computed (do not pass them); CHECK constraints are enforced.
Returns migrationId (undo) and the created path in plannedCreates.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
values |
object | yes | ||
body |
string \ | null | null |
|
path |
string \ | null | null |
|
dry_run |
boolean | false |
update_rows
Section titled “update_rows”Update Rows · write
Update every row matching where. where: keys AND-ed; values are equality or operators
eq, ne, gt, gte, lt, lte, in, contains, icontains (case/accent-insensitive, also inside lists —
use it for names and aliases), exists, within (a hierarchy link: that row and everything below);
combine with or / and / not (nestable); path is a pseudo-column. A dotted key follows a
link column: {"project.area": "[[Work]]"} matches rows whose project links a row with that area. set_values sets, unset
removes; all rows are validated first. body replaces the note body (only when one row matches).
expect_rows: refuse unless exactly that many match. One row: prefer update_row.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
where |
object \ | null | null |
|
set_values |
object \ | null | null |
|
unset |
string[] \ | null | null |
|
dry_run |
boolean | false |
||
body |
string \ | null | null |
|
expect_rows |
integer \ | null | null |
update_row
Section titled “update_row”Update Row · write
Update exactly ONE row, addressed by its id (the system UUID) or its path; refused when
the row does not exist (or id and path disagree). Same validation, journal and history as
update_rows.
set_values/unset: columns to set or remove.body: replace the whole note body; or edit it keeping the rest:body_sections{"Storia": "…"}replaces the text under that heading (any level, up to the next heading of the same level; added as## Storiawhen missing),body_prepend/body_appendadd text before / after.expect: compare-and-set —{"status": "open"}writes only if the row still has those values (a person may have changed it since you read it); otherwise refused, nothing written.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
id |
string \ | null | null |
|
path |
string \ | null | null |
|
set_values |
object \ | null | null |
|
unset |
string[] \ | null | null |
|
body |
string \ | null | null |
|
body_sections |
object \ | null | null |
|
body_prepend |
string \ | null | null |
|
expect |
object \ | null | null |
|
body_append |
string \ | null | null |
|
dry_run |
boolean | false |
delete_rows
Section titled “delete_rows”Delete Rows · destructive write
Delete rows matching where. mode: “archive” (default, move to the table’s archive
folder) or “delete” (trash; content journaled for undo). on_referenced: “restrict”
(default, refuse rows other notes link to), “set_null” (clear frontmatter links to them) or
“ignore”. Omitting where targets every row: always pass where unless you mean all.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
where |
object \ | null | null |
|
mode |
string \ | null | null |
|
on_referenced |
string \ | null | null |
|
dry_run |
boolean | false |
move_rows
Section titled “move_rows”Move Rows · write
Move rows matching where to another table (e.g. split a domain out of log into its own
table): sets each row’s table to the destination, applies rename ({"metric_distance_km": "distance_km"}), set_values and drop, adds the destination’s missing dense fields, and
validates every row against the destination first. Keys unknown to the destination are
reported, never dropped silently — rename or drop them explicitly. relocate=true also moves
the files to the destination table’s folder (named by its filename pattern). Undo with
undo_migration.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
to_table |
string | yes | ||
where |
object \ | null | null |
|
rename |
object \ | null | null |
|
set_values |
object \ | null | null |
|
drop |
string[] \ | null | null |
|
relocate |
boolean | false |
||
dry_run |
boolean | false |
adopt_rows
Section titled “adopt_rows”Adopt Rows · write
Turn existing notes (not rows of any table yet) into rows of table, keeping their body and
links: rename keys ({"data": "occurred_at"}), set_values for all, per_row values by
note path ({"Home/x.md": {"zone": "[[Kitchen]]"}}), drop keys the table does not have.
Every note gets table and a system id; with relocate (default) it moves to the table’s
folder, named by its filename pattern (links to it are rewritten). All notes are validated first:
unknown keys and bad values are listed and nothing is written. Run with dry_run first; undo
with undo_migration.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
paths |
string[] | yes | ||
rename |
object \ | null | null |
|
set_values |
object \ | null | null |
|
per_row |
object \ | null | null |
|
drop |
string[] \ | null | null |
|
relocate |
boolean | true |
||
dry_run |
boolean | false |
select_rows
Section titled “select_rows”Select Rows · read-only
Query rows: {table, total, rows: [{path, ...}]}. table may be a view,
system.information_schema.<catalogs|schemata|tables|columns|views|check_constraints>, or
base:<name> — every table that extends that base (e.g. base:record: all event-like tables),
on the base’s columns, each row tagged _source with its table.
where: as in update_rows; relative dates"{today}","{today-7d}","{now-24h}"; file columnsfile_name,file_link,file_modified,file_backlinks.columns,order_by(-coldescending),limit(default 100, max 1000),offset,expand(inline linked rows’ frontmatter),include_body(the note body asbody).join:{"table", "on": {"date(occurred_at)+1": "date(timestamp)"}, "as", "type": "inner"|"left", "columns", "where"}— matches attached underas.group_by(column,pathordate(col)±n; a list column counts once per item) +aggregates{"n": "count", "kcal": "sum:meal.kcal"}(count, count:col, sum, avg, min, max).- Ordered enums compare by position. Time travel:
versionortimestamp.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
columns |
string[] \ | null | null |
|
where |
object \ | null | null |
|
order_by |
string \ | string[] \ | null | |
limit |
integer \ | null | null |
|
offset |
integer \ | null | null |
|
expand |
string[] \ | null | null |
|
join |
object \ | null | null |
|
group_by |
string \ | string[] \ | null | |
aggregates |
object \ | null | null |
|
include_body |
boolean | false |
||
version |
integer \ | null | null |
|
timestamp |
string \ | null | null |
check_table
Section titled “check_table”Check Table · read-only
Validate every row against the table (required, types, ranges, enums, links, unknown columns, CHECK constraints, stale generated/identity values). Use it to find rows edited by hand that break the schema.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes |
undo_migration
Section titled “undo_migration”Undo Migration · destructive write
Revert a journaled table operation by its migrationId. Refused (nothing written) when any
touched note changed since; the conflicts are listed. The revert is a new version (UNDO) in
the transaction log.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
migration_id |
string | yes |
Batch · destructive write
Several writes that succeed or fail together. operations: [{"op": ..., ...arguments}] where
op is a row operation (insert_row, update_row, update_rows, delete_rows, merge_rows,
move_rows, adopt_rows, recompute_columns, align_relations, restore_table) or a DDL op
(create_table, add_column, alter_column, …), with the same arguments as its tool (e.g.
values for insert_row, set_values for update_row / update_rows). They run in order, each seeing the previous ones; if one is
refused, the ones already applied are undone (rolledBack). Returns steps (per operation) and
migrationId: undo_migration on it reverts the whole batch. Use it when a change spans several
rows (create an event and update the people in it). dry_run checks each operation against the
current data only.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
operations |
object[] | yes | ||
summary |
string \ | null | null |
|
dry_run |
boolean | false |
align_relations
Section titled “align_relations”Align Relations · write
Add the reciprocal links missing on a table’s inverse link columns (e.g. Alice lists Carol
in friends but Carol does not list Alice). Run it after declaring inverse on existing data;
check_table reports such rows (code inverse). Single-value links already pointing elsewhere
are conflicts (nothing written). Writes through the tools already keep both sides in step.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
paths |
string[] \ | null | null |
|
dry_run |
boolean | false |
infer_table
Section titled “infer_table”Infer Table · read-only
Read-only schema inference from notes’ frontmatter.
folder(recursive; “” = whole vault) and/orpaths: notes not yet in a table. Returnscolumns(type, enumvalues, linkrefto the table most targets belong to,required,unique,dense,fromwhen the property name is not a valid column name,stats),proposalready for create_table (name,options.filenameortimeColumn,columns) andadoptready for adopt_rows (paths,rename,relocate: false), plusnotesto read. Review the proposal (names, enums, required) before creating; ask the user when unsure.table: keys the table’s rows use but the table does not declare (candidates for add_column, or keys to drop from rows). A string column becomes an enum with at mostmax_enum_valuesdistinct values (default 12).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
folder |
string \ | null | null |
|
paths |
string[] \ | null | null |
|
table |
string \ | null | null |
|
name |
string \ | null | null |
|
max_enum_values |
integer \ | null | null |
semantic_search
Section titled “semantic_search”Semantic Search · read-only
Find notes by meaning, not exact words: {query, results: [{path, score, heading, snippet, table?}]}, one result per note (its best passage), best first. Use it for vague questions
(“the dinner where we talked about moving”, “what did I decide about the car”) and to find the
rows to read or update; then read_note / select_rows for the details. Filters: tables
(qualified or short names), folder, min_score (cosine 0–1; ~0.5+ is usually relevant).
limit: default 10, max 100. Fails with a clear message when semantic search is not enabled in
the engine settings.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | yes | ||
limit |
integer | 10 |
||
tables |
string[] \ | null | null |
|
folder |
string \ | null | null |
|
min_score |
number \ | null | null |
semantic_index
Section titled “semantic_index”Semantic Index · write
Semantic search index: status (enabled, provider, model, files, passages, pending,
running, lastSync, lastError), update (embed notes changed since the last run; the
engine also does it on its own about ten seconds after edits) or rebuild (re-embed
everything: slow, and costs money with a paid provider — ask first).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
action |
string | "status" |
list_migrations
Section titled “list_migrations”List Migrations · read-only
The operation journal, newest first: migration_id (for undo_migration), op, summary,
schema (table), executed_at, notes_changed, files, undone, undoes, failed.
Filters: op (e.g. “update_rows”), table (substring of the table name, e.g.
“personal.tasks.task”), since (ISO date). limit default 50. The journal is kept in the
vault’s hidden .datanotes/journal/ (not notes); entries older than 90 days are dropped.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
integer \ | null | null |
|
op |
string \ | null | null |
|
table |
string \ | null | null |
|
since |
string \ | null | null |
merge_rows
Section titled “merge_rows”Merge Rows · write
MERGE (upsert) rows into table by the key columns on (e.g. ["occurred_at"] or
["id"]): a row matching an existing one updates it (when_matched: “update” default or
“ignore”), the others are inserted (when_not_matched: “insert” default or “ignore”).
Date-times are compared after completion with the database time zone. A source key matching
several rows, or repeated, is a conflict. One journaled, undoable operation.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
on |
string[] | yes | ||
rows |
object[] | yes | ||
when_matched |
string \ | null | null |
|
when_not_matched |
string \ | null | null |
|
dry_run |
boolean | false |
describe_history
Section titled “describe_history”Describe History · read-only
DESCRIBE HISTORY: the table’s versions, newest first — version, timestamp, operation
(CREATE TABLE, WRITE, UPDATE, DELETE, MERGE, ALTER TABLE, ADD COLUMNS, RESTORE, UNDO, …;
EXTERNAL_EDIT = changed outside the engine: an editor, git, sync), operationMetrics and migrationId (undo).
Works for dropped tables too (full catalog.schema.table). Use a version with select_rows
(time travel), table_changes or restore_table.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
limit |
integer \ | null | null |
table_changes
Section titled “table_changes”Table Changes · read-only
Change data feed between two versions (both included, end defaults to latest): one entry
per row change with its values plus _change_type (insert, delete, update_preimage,
update_postimage, metadata), _commit_version, _commit_timestamp, _operation, path.
Use it to answer “what changed since …” without diffing full tables.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
start_version |
integer | yes | ||
end_version |
integer \ | null | null |
list_changes
Section titled “list_changes”List Changes · read-only
Change feed across all tables: numbered row changes (seq), oldest first, from engine writes
and from hand edits (source: external). Each has table, op (insert, update, delete, move,
schema), path, changes ({column: {before, after}}), actor, migration. Agents’ tool calls (reported by MCP servers) are op: tool_call events (call: tool, args, ok, value, servedBy), returned only when ops includes tool_call. Pass the returned
last as since next time (head is the newest number); wait_ms (max 60000) waits for a new change (long poll); limit max 5000. gap: true means
older changes were dropped: re-read the tables. where filters rows as in select_rows (on the values after the change). Per-table versions: table_changes.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
since |
integer | 0 |
||
tables |
string[] \ | null | null |
|
ops |
"insert" \ |
"update" \ |
"delete" \ |
"move" \ |
columns |
string[] \ | null | null |
|
where |
object \ | null | null |
|
exclude_actor |
string \ | null | null |
|
limit |
integer | 500 |
||
wait_ms |
integer | 0 |
list_webhooks
Section titled “list_webhooks”List Webhooks · read-only
Webhooks of the change feed: id, url, filter (tables, ops, columns, exclude_actor), cursor (last change delivered), status (ok, failing, disabled), lastDelivery, lastError. Secrets are not shown.
create_webhook
Section titled “create_webhook”Create Webhook · write
Push row changes to a URL (a service that would rather be called than poll list_changes): batches of up to 100 events POSTed as {webhook, events, last}, signed with X-Datanotes-Signature: sha256=<HMAC of the body>, retried with backoff until a 2xx. Starts from now unless since. Returns the webhook with its secret — shown only here: give it to the receiver.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string | yes | ||
tables |
string[] \ | null | null |
|
ops |
"insert" \ |
"update" \ |
"delete" \ |
"move" \ |
columns |
string[] \ | null | null |
|
exclude_actor |
string \ | null | null |
|
where |
object \ | null | null |
|
since |
integer \ | null | null |
delete_webhook
Section titled “delete_webhook”Delete Webhook · destructive write
Stop and remove a webhook (by id from list_webhooks).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | yes |
restore_table
Section titled “restore_table”Restore Table · destructive write
RESTORE TABLE to a version or timestamp: rows and definition return to that state —
rows added since are deleted, changed rows get their old content, removed rows come back (a
dropped table is re-created). History is not rewritten: the restore is a new version, and
undo_migration reverts it. Run with dry_run first and show the user what changes.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
version |
integer \ | null | null |
|
timestamp |
string \ | null | null |
|
dry_run |
boolean | false |
vacuum_table
Section titled “vacuum_table”Vacuum Table · destructive write
Delete transaction-log history older than retain_from_version (default: keep only the
latest version); time travel before it becomes impossible. Rows are not touched. dry_run
defaults to true: it lists the log files that would go. Only on the user’s explicit request.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
retain_from_version |
integer \ | null | null |
|
dry_run |
boolean | true |
add_constraint
Section titled “add_constraint”Add Constraint · write
ALTER TABLE ADD CONSTRAINT name CHECK: check is a where filter every row must match,
e.g. {"value": {"gte": 1, "lte": 5}} (a condition on an empty value passes, like SQL).
Refused while existing rows violate it (they are listed); then enforced on every write.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
name |
string | yes | ||
check |
object | yes | ||
dry_run |
boolean | false |
drop_constraint
Section titled “drop_constraint”Drop Constraint · write
Remove the CHECK constraint name from table.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
name |
string | yes | ||
dry_run |
boolean | false |
create_view
Section titled “create_view”Create View · write
Create (or replace) a view: a named select stored in database.yaml. Name it with the prefix
vw_ (e.g. vw_open_tasks): views share names and folders with tables. query takes the
select_rows parameters (table, columns, where, order_by, limit, join, group_by, aggregates, expand;
relative dates keep it current) and must run now. comment and aliases let agents find it;
labels are column headings. Read it with select_rows(table=view: <name> (drawn live by the client; nothing is written into
the note). Filters may read the note that shows the view: {this.date}, {this.date+1d} (a
frontmatter value, date arithmetic), {this.link} (a link to that note), {this.name}. The view
also gets a note in its schema folder.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | ||
query |
object | yes | ||
catalog |
string \ | null | null |
|
schema |
string \ | null | null |
|
comment |
string \ | null | null |
|
aliases |
string[] \ | null | null |
|
labels |
object \ | null | null |
|
replace |
boolean | false |
||
dry_run |
boolean | false |
drop_view
Section titled “drop_view”Drop View · destructive write
Remove a view from database.yaml (undo with undo_migration).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
view |
string | yes | ||
dry_run |
boolean | false |
clone_table
Section titled “clone_table”Clone Table · write
CREATE TABLE target CLONE source: same definition plus independent copies of its rows
(deep clone), optionally as of a version / timestamp. shallow=true copies the
definition only (CREATE TABLE LIKE). target: catalog.schema.table, schema.table (in the
source’s catalog) or a name (source’s catalog and schema). Useful for experiments, e.g. a sandbox copy
in the agent catalog.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
source |
string | yes | ||
target |
string | yes | ||
version |
integer \ | null | null |
|
timestamp |
string \ | null | null |
|
shallow |
boolean | false |
||
dry_run |
boolean | false |
recompute_columns
Section titled “recompute_columns”Recompute Columns · write
Bring generated and identity columns up to date (all rows, or only paths), e.g. after
rows were edited by hand (an editor, git, sync) or a generated expression changed with alter_column.
Also gives rows without an id a new one, and a duplicated note (same id as an older row)
a new id. new_ids=true regenerates every id in scope (new ones on every call): only on the user’s
explicit request.
check_table reports stale values with code generated. No-op when nothing is stale;
otherwise journaled (undo_migration) and a RECOMPUTE version in the table’s history.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
table |
string | yes | ||
paths |
string[] \ | null | null |
|
new_ids |
boolean | false |
||
dry_run |
boolean | false |
graph_neighbors
Section titled “graph_neighbors”Graph Neighbors · read-only
Direct neighbours of notes: what they link to (out) and what links to them (in,
backlinks), with counts per edge label. direction: out, in or both (default).
from_nodes selects the notes: {"paths": [...]} and/or {"table": ..., "where": {...}}.
Edges are labelled with their link column (people, event, …) or link for other links.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
from_nodes |
object | yes | ||
direction |
string \ | null | null |
|
edges |
string[] \ | null | null |
graph_traverse
Section titled “graph_traverse”Graph Traverse · read-only
Breadth-first walk over links from from_nodes ({"paths": [...]} and/or {"table", "where"}).
direction: out (default, follow links), in (follow backlinks) or both.edges: edge labels to follow (link columns such aspeople,event, orlink).tables: return only notes of these tables;through: only walk on through these tables.min_depth(default 1) /max_depth(default 2, max 10),limit(default 500).
Each node comes with depth and via (one shortest route). Example — moods tied to events
with Alice: from {"table": "person", "where": {"name": "Alice"}}, direction in, edges
["people", "event"], tables ["mood"], max_depth 2. Feed the paths to select_rows with
where: {"path": {"in": [...]}} to aggregate them.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
from_nodes |
object | yes | ||
direction |
string \ | null | null |
|
edges |
string[] \ | null | null |
|
tables |
string[] \ | null | null |
|
through |
string[] \ | null | null |
|
min_depth |
integer \ | null | null |
|
max_depth |
integer \ | null | null |
|
limit |
integer \ | null | null |
graph_path
Section titled “graph_path”Graph Path · read-only
Shortest chain of links between two sets of notes (each {"paths": [...]} and/or
{"table", "where"}): found, length and path: the steps (from, label, direction, to).
direction both by default; max_depth default 6 (max 10).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
from_nodes |
object | yes | ||
to_nodes |
object | yes | ||
direction |
string \ | null | null |
|
edges |
string[] \ | null | null |
|
max_depth |
integer \ | null | null |