Skip to Content
Gnomon Docs
Reference

SQL reference

All functions live in schema gnomon. References (ref) accept main, a branch name, branch@<coordinate ref>, a coordinate (e1:880:882:881@0/1A2B3C4), tag:<name>, now, or a timestamp (resolved to the latest clock tick at or before it).

Session settings

SettingMeaning
gnomon.branchbranch name (empty or main for main)
gnomon.as_ofread point: coordinate, tag:<name>, now, or timestamp (read-only)
gnomon.valid_atvalid-time read point for bitemporal tables
gnomon.valid_fromvalid-time write point (a future value schedules the change)
gnomon.actor, gnomon.reasoncommit-log attribution for the transaction
gnomon.standby_waithow long gnomon.use()/wait_for() wait on a standby for replay (default 30 seconds)
gnomon.routing (C module)off disables transparent routing for the session
gnomon.track_reads (C module)record keys read on a branch, for stale-read detection
gnomon.c_substitute (C module)off makes the session use the SQL core's read context and probes instead of the C module's
gnomon.c_point_reads (C module)off turns off the point-read path: SELECT ... WHERE <key> = <value> on one routing view is otherwise answered by the GnomonPoint custom scan, with the same rows as the view
gnomon.c_touched_filter (C module)off makes branch point reads scan the touched keys even when the shared-memory filter says no level touched the key (gnomon.touched_filter_kb, a server setting, sizes the filter; 0 turns it off)
gnomon.c_direct_inserts (C module)off makes the C trigger insert versions through SPI plans instead of directly into the partition

All work with SET, SET LOCAL, set_config(..., true) and options=-c ....

Tracking

The functions of this section may be called by a superuser, the role that installed gnomon, or a member of gnomon_admin that owns the table. Renaming a tracked table or moving it to another schema keeps it tracked.

Function
track(tbl, mode => 'known'|'bitemporal', write_mode => 'row'|'statement', key => name[], key_index => 'brin'|'btree', part_span => int8, merge => jsonb, protected => bool)Start versioning a table (needs a primary key or a unique NOT NULL key). No backfill; metadata-only locks with lock_timeout and retries. Returns the tracked id.
track_schema(schema, mode, write_mode)Track every table with a primary key.
untrack(tbl, keep_history => false)Removes gnomon's triggers, policies and routing view (and storage unless kept); RLS gnomon enabled is turned off, RLS the table had of its own stays.
sync(tbl => null)Re-generate gnomon's objects after DDL (automatic with event triggers).
set_write_mode(tbl, 'row'|'statement')Row triggers for OLTP, statement triggers for bulk loads.
set_merge_strategy(tbl, col, strategy)conflict, ours, theirs, counter, jsonb, set, text3, or a function (base jsonb, ours jsonb, theirs jsonb) -> jsonb (null: a conflict), resolved on your search_path and stored schema-qualified.
protect(tbl, on_off)Changes only through merges.
outbox(tbl, channel)Held outbox: NOTIFY on main inserts (branch rows deliver when merged).
use_c_trigger(tbl, on_off) (gnomon_c)Switch to the C versioning trigger.

Coordinates, time

Function
coordinate(), coordinate_text()The calling statement's snapshot as a coordinate (primary only).
coord(text), coord_text(coord)Parse and print.
resolve_coord(ref)Any reference to a coordinate.
wait_for(coord or text, timeout => gnomon.standby_wait)On a standby, wait until it has replayed past the coordinate; statements that start afterwards read it exactly (call it before BEGIN under REPEATABLE READ). use(), as_of() and begin() call it. No-op on a primary.
heartbeat()Tick, scheduled changes, watch, ledger, partitions, scratch sweep, retention. Takes no xid and writes nothing when nothing changed.
tick()A tick only: the coordinate now with the wall time, written only when something changed since the last (gnomon_admin).
current_epoch()
create_tag(name, at => 'now', note), drop_tag(name)Name a coordinate (it pins retention); as_of = 'tag:name'. A tag's creator or gnomon_admin drops it.
history_pins()(kind, what, coord, all_after): what still needs main's history (branch cutoffs, unapplied merge bases, feed consumers, the last ledger block, the watch point); retention, archiving and drop_history_before keep it.

Branches

Function
create_branch(name, parent => 'main', kind => 'logged'|'scratch', at => ref, ttl => interval, note => text)
create_scratch(prefix, parent, ttl)Returns a generated name.
use(branch, as_of => null, local => false), begin(branch, as_of)Put the session or transaction on a branch. Returns the search_path.
as_of(ref), current_branch()
drop_branch(name, cascade), close_branch(name), reopen_branch(name)
sweep_scratch()Drop lost and abandoned scratch branches; never one a session is still using (it holds a lock on it).
truncate(tbl)TRUNCATE on a branch.
confine(role, branches, allow_create, mask_profile), allow(role, branch, can_write), unconfine(role)
connection_options(branch, c_module), routing_path(base_path)
track_reads(branch, sample => 1.0)Read-set tracking for stale reads on this branch (C module): gnomon.use() turns it on; null falls back to read_sample and the session setting.
view branchesname, parent, kind, status, base, rebases, behind (versions main wrote since the base)

Reading history

FunctionReturns
diff(a, b => null, tables => null, keys => null)(tbl, key, kind, col, old, new): one row per changed field; diff(branch) compares a branch with its base.
diff_summary(a, b)inserts, updates, deletes per table
changes(since, until => now, tables => null, images => true)(vkey, vlsn, tbl, key, op, xid, role, new, old): exactly the versions visible at until and not at since, in commit-consistent order. images => false leaves new and old null: the same change set at the speed of the version scan.
feed_create(consumer, since), feed_poll(consumer, lim), feed_drop(consumer)A consumer's next batch; positions are stored, and pages follow the last change returned (a poll costs its page, not the window). A consumer belongs to its creator (or gnomon_admin) and keeps its unread history from retention: drop it when done.
history(tbl, key jsonb)every version of a row (baseline, inserts, updates, deletes); at is the commit time with track_commit_timestamp, else the commit log's, else the first tick's (at_tick)
blame(tbl, key jsonb)per column: the version, role, actor and time (at, as in history) of its last change
stale_reads(branch)keys a branch read (C module tracking) that its target changed since the read

Merging

Function
merge(source, target => parent, mode => 'atomic', tables => null, keys => null, resume => null, close => false)Returns the merge id. Status applied or conflicts.
merge_incremental(source, target, batch, resume) (procedure, CALL)A commit per batch: inserts and updates parents first, then deletes children first; each batch is locked, planned and applied once; the same approvals, stale-read check and merge checks as merge. Stops at conflicts (resolve, then resume => id); a failing check marks it failed (resume, or undo_merge).
merge_preview(source, target, tables, keys)(tbl, key, action, base, ours, theirs, result, conflicts)
merge_where(source, tbl, predicate, target, preview => false)Partial merge by a key predicate (SQL over the key columns), evaluated with the caller's rights.
resolve(conflict_id, 'ours'|'theirs'|'base'|'value', value jsonb), resolve_all(merge_id, choice)
rebase(branch, at => now)Carry a branch onto its parent's current state; conflicts land in gnomon.conflict with branch set.
watch()Early warnings into gnomon.warning: keys main changed that a branch touched, and branches warn_changes_since_base behind (rebased instead with auto_rebase = on).
undo(xid, branch => 'main'), undo_xids(xids, branch, why), undo_merge(id), undo_role(role, since, until, branch)Reverts through the merge engine; later edits to the same fields refuse the undo (40001).
tables merge, conflict, warning, xactrecords

Review and control

Function
open_change_request(branch, title, body, target, approvals), review(cr, 'approve'|'reject'|'comment', body)
add_check(name, sql, expect => 'empty'|'nonempty'|'true', target), drop_check(name)Checks run on request and inside every merge into their target.
run_checks(branch, cr)
create_mask_profile(name), add_mask_rule(profile, tbl, col, expr), build_mask_profile(profile)Masked routing schemas.
outbox_poll(consumer, tbl, lim)Outbox rows that reached main.
note(actor, reason, meta)Attribution for the current transaction.
postgrest_pre_request(), postgrest_config(c_module)PostgREST / Supabase.

Valid time

Function
correct(tbl, key, valid_from, valid_to, changes jsonb)A correction for [valid_from, valid_to).
apply_scheduled()Apply future-dated changes that came due (the heartbeat does).

History management

Function
set_retention(tbl, policy jsonb), apply_retention(tbl){"keep_all": "30 days", "daily": "1 year", "monthly": true}
drop_history_before(tbl, before, force => false)Drop whole version partitions; refuses history something still needs (history_pins()) unless forced.
archive_partition(tbl, part, uri, rows, checksum), restore_partition(tbl, part), restore_done(tbl, part)Used by gnomon archive / restore.
erase(tbl, key, columns, reason)
seal_ledger(), verify_ledger(), ledger_digest()Leaves (format 2) hash a version by table id, key values and one hash per value slot: renames and other DDL leave sealed history verifiable; an erased value is checked against the hash erase() recorded.
doctor(sample)
set(name, value), view settings

More settings

Set with gnomon.set(name, value); the view gnomon.settings lists every setting with its documentation. stale_approvals (dismiss), runs_role, logged_ttl (off), expire_grace (7 days), merge_window (HH:MM-HH:MM, empty: any time), idle_review_after (off), checkpoints (off), feed_setbased_min (20000), feed_c (off; on: the C module's feed arm), thaw_max_rows, thaw_ttl (1 day), thaw_wait (off), review_url, ddl_lock_timeout (5s), ddl_concurrent_rows (1000000), cold_scans (thaw: a read that needs history in an archive read in place requests a thaw; allow: it scans the archive through its foreign partition; refuse: 55000). Every gnomon error's hint ends with a stable [gnomon:<slug>]; errors.md lists them.

Developer experience

Function
status()One JSON document: the branch the session names and whether it is routed there, the as-of reference, SQL core or C module, changes per table, distance from main, warnings, change request and whether its approval is stale, quota used, the last tick's age.
assert_routed()Raises when gnomon.branch names a branch but unqualified names do not resolve to its routing views (call it at start-up).
describe(schema => null)Tables the role can read, columns, keys, foreign keys both ways, tracked/protected/outbox, masked columns, row estimates, and the session's branch, base, write rights and quota.
primary_key(rel)The key columns of a table or of its routing view (tools that look keys up on a branch).
explain_error(sqlstate, message)What an error means on a branch (upserts in the SQL core, untracked tables, confined roles, slugs), or null. The CLI, the MCP server and the SDKs append it.
api_version()2. The SDKs check it when they connect.
connection_options(branch, c_module => false)libpq options for a branch: knows scratch branches, the caller's mask profile and the branch's schema version.
use(branch, as_of, local, mode => 'routing'|'search'), begin(branch, as_of, mode)As above, plus: the reference is resolved when called; archived history it needs is requested for thawing; mode => 'search' puts the search views first.

Branches as roles, quotas, expiry

Function
assign(role, branch, base_path), unassign(role)Every new session of the role starts on the branch (role defaults for gnomon.branch and search_path). Admin only; a privileged role only by a superuser.
set_quota(scope => 'default'|'role'|'branch', name, max_branches, max_rows, max_age, max_children), effective_quota(role, branch), branch_usage(branch)Limits. Row and age limits are checked by the heartbeat, which marks a branch over quota; writes to it are refused (53400).
set_branch_ttl(branch, ttl), expire_branches()A branch unused for its ttl is closed, then dropped expire_grace later (skipped with an open change request or open children).
set_auto_rebase(branch, 'off'|'clean'|'always'), auto_rebase_branches(idle)The heartbeat rebases an idle branch that main has left behind (clean: only when the rebase has no conflicts).
rebase(branch, at, dry_run => false)dry_run reports what a rebase would do and rolls it back.

Runs and agents

Function
run_start(task, actor, kind, ttl, parent), run_end(branch, keep, outcome)A branch for one run, writable by the runs login (runs_role); members of gnomon_runner. The runs login's transactions are bound to one run each.
run_login(branch)A login of the run's own (gnomon_run_<hash>, a member of the runs role, confined to the run's branch, its sessions starting there): {role, password, branch, options}. What the SDKs' run.url() and run.connection() hand out; run_end drops it and ends its sessions.
agent_create(name, parent, password, mask_profile, allow_create, note)A login role gnomon_agent_<name>, confined, assigned to branch <name>/1, with a token; returns the connection string and the MCP configuration.
agent_next(name, parent), agent_rotate(name), agent_auth(token), agent_stop(name, undo_since), set_agent_budget(name, calls_per_minute, max_result_rows, max_result_bytes), view agent_usageA fresh branch per task; a new token; the HTTP server's token check; the kill switch (token off, NOLOGIN, sessions ended, branches closed, optionally the agent's merges undone); budgets.
record_call(run, tool, args, branch, coord, xid, rows, digest, error, agent), verify_run(run)The hash-chained run record and its check.
done(summary)Opens (or comments on) the change request for the session's branch.

Review

Function
review_stale(review_id)Whether the branch changed after the review (stale approvals do not count).
change_request_status(cr), run_summary(branch, run_checks)One JSON document each: reviews (stale ones marked), comments, check runs, merge state; or a branch's changes, checks, conflicts a merge would hit, and warnings.
wait_for_review(cr, timeout)Returns the status when a review arrives, the request is merged or closed, or the timeout passes.
comment(cr, body, tbl, key, col), resolve_comment(id)Comments anchored to a row or a field.
diff_keys(a, b, tbl, after, lim)A page of the keys that can differ between two references, in key order.
add_notify_target(name, 'webhook'|'channel', config, events)Where "change request opened" goes: a webhook (delivered by the daemon) or a NOTIFY channel.
create_merge_policy(name, agents, rules, target), drop_merge_policy(name), policy_eval(branch, policy)Auto-merge policies (rules: max_rows, max_rows_per_table, tables, columns, ops, no_stale_reads, window, max_base_lag; protected and outbox tables are refused unless allow_protected/allow_outbox; conflicts stop the merge and checks run in it as always); a caller without gnomon_merger may merge a covered branch when every rule holds for the plan.
schedule_merge(branch, at, close, require_checks), cancel_scheduled_merge(id), run_scheduled_merges()Merges run later by the daemon, re-checked then.

Workflows

Function
merge(source, target, ..., strict => false)Any open target: siblings merge from their common base; repeat merges from the last one; strict refuses to carry the parent's changes a newer source forked with.
cherry_pick(xids, source, target)What some transactions of a branch did, applied three-way to another branch.
revert(tbl, at, keys, filter, columns, branch, dry_run), revert_tables(tbls, at, ...)Set rows back to their state at a past moment (undoable).
checkpoint(name, branch), rewind(branch, to, dry_run)A tag on a branch; set the branch back to it.
dry_run(statements, branch, checks)Run statements on a throwaway child, return the diff, checks and warnings, keep nothing.
attempts_create(n, prefix, parent), compare(branches), attempts_pick(group, winner, title)Parallel attempts at one coordinate, compared by checks, diff and conflicts.
scenario_create(name, parent, kind, note), scenario_apply(name, sql), add_metric(name, sql, unit), compare(scenarios, metrics, baseline_at), scenario_promote(name, title)What-if branches and metrics.
bisect(check, good, bad, branch)The transaction where a check started failing.
create_action_table(name, channel, schema)A tracked outbox table for side effects that run on merge.

Time, graph, metrics

Function
history(tbl, key, branch), blame(tbl, key, branch), log(branch, lim)On any branch; on_branch says where each version was written.
changes(since, until, tables, images => 'none'|'new'|'both')The feed, with the image mode named (the boolean form still works); includes truncate changes.
scd2(tbl, view_name), scd2_changes(tbl, since, until)A type-2 slowly changing dimension view, and its incremental feed.
series(tbl, key, col, since, until, branch), metric_series(sql, since, until, step, max_points, branch, timeout), metric_series_incremental(tbl, agg, col, filter, since, until), events(tbl, key, depth, since, until, max_neighbors)A value over time, a query at each step, a sum or count from the feed, a row's and its neighbours' changes.
neighbors(tbl, key, depth, direction, max_rows, links), link(name, from_tbl, from_cols, to_tbl, to_cols, filter), impact(branch, max_context)Rows related by foreign keys and declared links, through the session's branch and time; a branch's diff as a graph.
metrics(per_branch, max_branches), metrics_text(per_branch)Gauges and counters from catalogs; the Prometheus text /metrics serves.
history_checkpoint(tbl, at), drop_history_checkpoint(tbl, id), set_checkpoint_policy(tbl, every, keep), run_checkpoint_policies()Full images that make past scans cheap (with checkpoints = on).
truncate(tbl)On main too: a checkpoint, a marker, then the truncate.
thaw_needed(at), request_thaw(at), thaw_status(), refreeze_expired()Archived partitions a moment needs, and their thawing (the daemon calls thaw_take/thaw_finish).
CALL thaw(at, wait => '5 minutes')Request the thaw a moment needs, commit, and wait until the daemon has restored it (outside a transaction block). With the setting thaw_wait (or the session's gnomon.thaw_wait), use() and begin() also wait, for requests made before their transaction.
archive_partition(..., keep => true, format => 1|2)Used by gnomon archive: keep thins the partition locally instead of dropping it; format 2 is typed Parquet with row groups and Bloom filters on key columns (format 1: text columns).
attach_archive(tbl, part, engine, location), detach_archive(tbl, part)Read an archived partition in place: a foreign table over the archive file attached as the history partition, made from an engine's template in gnomon.archive_engine (file_fdw over the archive's CSV copy, duckdb_fdw, pg_lake). gnomon archive --engine calls it; restore_partition detaches first.
set_subject(tbl, subject_col, columns), archive_crypto(tbl), subject_keys(tbl, subjects, create_missing), erase_subject(tbl, subject, reason)Crypto-shredding: the archiver encrypts columns with a key per data subject (AES-256-GCM); erase_subject deletes the key (every archive forgets the subject's values, object-locked stores included), erases the columns in the database, and records it in gnomon.subject_erased. Admin only.
dbt_snapshot(tbl, target, consumer)Keeps target in dbt's snapshot shape (dbt_scd_id, dbt_valid_from, dbt_valid_to, dbt_updated_at) from the feed: the first run loads the current rows, later runs apply only what changed; the gnomon_dbt package's gnomon_history materialization calls it.

Sinks and masks

Function
sink_add(name, 'webhook'|'file'|'nats'|'kafka'|'parquet', config, tables, format => 'gnomon'|'debezium'|'cloudevents', since), sink_status(name, 'active'|'paused'), sink_replay(name, since), sink_drop(name)Deliveries of the feed, run by the daemon (sink_batch, sink_report). Kafka: config.brokers (host:port, comma separated), config.topic (default gnomon.changes; create it first); an idempotent producer, a row's key as the message key. Parquet: config.to, a directory or store URL (s3://, gs://), one file per batch, named by the batch so a retry overwrites its own file.
sink_state(name, state)The daemon saves a sink's delivery state (the Kafka producer id, epoch and sequences) in the delivery's transaction.
mask_hash(value, salt), mask_int(value, salt), mask_email(value, salt)Deterministic masks for key and foreign-key columns (doctor warns about others there).
save_graph_view(name, tbl, key, depth, branch, at, note), graph_views(), drop_graph_view(name)Saved views of the review app's graph page; listed for roles that may read the table, changed or dropped by whoever saved them (or gnomon_admin).
verify_ledger()As above, and records each run in gnomon.ledger_verification for the metrics (gnomon_ledger_verification_ok).
_gnomon.c_counters()With the C module: its counters summed over every session (shared memory).

Schema changes on a branch

Function
ddl(statement, up => null, down => null)On a branch: runs the statement against the branch's schema version (made on its first DDL) and records it; the session then reads the new shape. On main: plain DDL. Takes ADD COLUMN (nullable or a constant default; NOT NULL needs a default), CREATE TABLE (with a primary key), CREATE INDEX (unique ones become unique constraints of the version), comments; constraints: SET/DROP NOT NULL, CHECK, UNIQUE, foreign keys, DROP CONSTRAINT of a branch's own, each checked against the branch's rows when added and enforced on its writes; SET/DROP DEFAULT; RENAME COLUMN, DROP COLUMN, ALTER COLUMN ... TYPE (up: main's value in the new type, an expression over the column; down: a branch value in main's type, for writes through main's columns; both default to casts), DROP TABLE. Refused by name: key columns renamed, dropped or retyped, primary keys and exclusion constraints, volatile defaults, expressions outside pg_catalog, statements that reach main. Name tables without a schema.
schema_changes(branch)The changes a branch's version carries.
schema_diff(branch)Values the branch set in its added columns.

A branch on a version is merged into main (or a child into its parent on the same version): the merge replays the DDL on main first (constraints NOT VALID, then validated; a type change converts main's history with up). What main has since done in another way is a conflict of kind schema: a table or column the branch changes that main dropped or renamed, a column both added with different types, a rename onto a name main took, a table both created, a constraint of the same name with another definition, a foreign key to a table main dropped. The same change made on both sides is adopted.

On this page