Skip to main content

System Reference

This page documents all built-in system modules, tables, views, and functions that are available in every hugr instance. These modules are automatically loaded at startup and provide core infrastructure for data source management, schema introspection, clustering, GIS operations, object storage, and node information.

core Module

The core module manages data sources, catalog sources, roles, API keys, and provides lifecycle functions for loading/unloading data sources.

Tables

data_sources

Registered data sources. Each entry defines a connection to an external database or service.

FieldTypeDescription
nameString! (PK)Data source name
typeString!Source type: duckdb, postgres, http, extension
prefixString!Prefix added to all types in this source. When as_module is true, queries are placed in a separate module
as_moduleBoolean!Whether to expose as a separate GraphQL module (default: false)
descriptionStringHuman-readable description
pathString!Connection path (DB file path, connection string, or URL depending on type)
disabledBooleanDisable without removing (default: false)
self_definedBooleanIf true, the source returns its own schema definition (default: false)
read_onlyBooleanRead-only mode (default: false)

catalog_sources

Schema catalog sources that provide GraphQL schema definitions for data sources.

FieldTypeDescription
nameString! (PK)Catalog source name
typeString!Source type: localFS (local directory) or uri (remote file)
descriptionStringHuman-readable description
pathString!Path to schema files (directory path or URI)

catalogs

Many-to-many mapping between data sources and catalog sources.

FieldTypeDescription
catalog_nameString! (PK)References catalog_sources.name
data_source_nameString! (PK)References data_sources.name

roles

Permission roles that can be assigned to users and API keys.

FieldTypeDescription
nameString! (PK)Role name (built-in: admin, public, readonly)
descriptionString!Role description
disabledBooleanDisable the role (default: false)

role_permissions

Fine-grained permissions controlling visibility and access to types and fields per role.

FieldTypeDescription
roleString! (PK)References roles.name
type_nameString! (PK)Type name (* for all types), or a data-object:<op> marker (see below)
field_nameString! (PK)Field name (* for all fields); for data-object:* rows, the data object's GraphQL type name (or *)
hiddenBooleanHide from schema introspection (default: false)
disabledBooleanDeny access (default: false)
filterJSONRequired filter values for queries
dataJSONRequired field values for mutations

Matching precedence for field-level rows is most-specific first: exact (type_name, field_name) > (type_name, *) > (*, field_name) > (*, *); with no matching row, access is allowed by default.

A type_name of the form data-object:query, data-object:insert, data-object:update, or data-object:delete makes the row a table-level (data-object) rule instead of a field-level one. field_name then holds the data object's GraphQL type name (or *). These rules apply wherever the table is materialised — direct query, _by_pk, relations, _join, aggregations, and mutations — and compose with field-level rules (filters by AND, disabled by OR, mutation data force-stamped last). See Access Control → Data-Object Permissions.

api_keys

API keys for authentication with optional role binding and expiration.

FieldTypeDescription
nameString! (PK)API key name
descriptionString!Description
keyString!API key value (unique)
default_roleStringReferences roles.name
disabledBooleanDisable the key (default: false)
is_temporalBooleanWhether the key expires (default: false)
expires_atTimestampExpiration date (required if is_temporal is true)
headersJSONHTTP header mapping for extracting user info: {"role": "x-role", "user_id": "x-user-id", "user_name": "x-user-name"}
claimsJSONStatic claims. The role/user_id/user_name keys set the identity; any other scalar key is exposed as an [$auth.<claim>] permission variable (see Custom Claim Variables)

Functions

load_data_source

Load or reload a data source catalog into the engine.

mutation {
load_data_source(name: "my_source") {
success
message
}
}
ArgumentTypeDescription
nameString!Data source name to load

Returns: OperationResult

unload_data_source

Unload a data source catalog without deleting its configuration.

mutation {
unload_data_source(name: "my_source") {
success
message
}
}
ArgumentTypeDescription
nameString!Data source name to unload

Returns: OperationResult

checkpoint

Force a DuckDB checkpoint (flush WAL to disk).

mutation {
checkpoint(name: "my_db") {
success
message
}
}
ArgumentTypeDescription
nameStringDatabase name (empty string for default)

Returns: OperationResult

data_source_status

Get the current status of a data source.

{
data_source_status(name: "my_source")
}
ArgumentTypeDescription
nameString!Data source name

Returns: String (status text)

describe_data_source_schema

Describe the schema of a data source. Useful for debugging schema compilation.

{
describe_data_source_schema(name: "my_source", self: true, log: false)
}
ArgumentTypeDescription
nameString!Data source name
selfBooleanShow the self-defined schema (default: false)
logBooleanInclude compilation log (default: false)

Returns: String (schema description)


core.catalog Module

The core.catalog module is the curation and maintenance surface of the catalog: it holds the annotate_* mutation functions and the schema-maintenance operations. See Curation Functions and Catalog Maintenance Functions.

Reading the catalog has two surfaces instead:

  • core.catalog.* views — the logical model as plain rows, an administrative surface that executes entirely inside the CoreDB engine and supports semantic search.
  • _catalog meta queries — request-scoped, permission-filtered introspection for clients.
Replaced in CoreDB 0.0.20

The read-only views this module used to publish over the compiled schema (catalogs, types, fields, arguments, modules, module_catalogs, data_objects, data_object_queries, module_intro, enum_values) are gone, together with the _schema_* tables behind them. A schema is no longer compiled and stored as GraphQL type rows: the logical model is stored instead, and the served surface is generated from it on read.

Migration at a glance:

Was (compiled schema)Now (logical model)
core.catalog.catalogscore.catalog.active_sources, core.catalog.stored_catalogs
core.catalog.catalog_dependenciescore.catalog.catalog_dependencies
core.catalog.modules, module_catalogs, module_introcore.catalog.modules, core.catalog.module_data_sources, core.catalog.functions
core.catalog.typescore.catalog.data_objects (tables/views) and core.catalog.types (source-declared types)
core.catalog.fields, arguments, enum_valuescore.catalog.fields; function arguments are structured in core.catalog.functions.args
core.catalog.data_objects, data_object_queriesgenerated on read — query the GraphQL schema through __schema / _catalog
Same names, different rows

Several names appear on both sides. The core.catalog module was rebuilt on the logical model, and the views that live there now answer a different question than the compiled-schema views of the same name did: core.catalog.types used to list every generated GraphQL type and now lists the residual source-declared types; core.catalog.fields used to be GraphQL field rows and is now data-object fields; core.catalog.modules is the module tree rather than compiled module records.

A query written against the old views will not error — it will return different data, or fail on a column that moved. Check the column lists below rather than assuming a name that still resolves means what it did.

:::


core.meta Module

The core.meta module exposes DuckDB system catalog views for introspecting the underlying database engine. All views are read-only.

Functions

duckdb_version

Returns the DuckDB engine version string.

{
core_meta {
duckdb_version
}
}

Views

databases

Attached DuckDB databases.

FieldTypeDescription
idBigInt! (PK)Database OID
nameString!Database name (unique)
typeString!Database type
commentStringComment
readonlyBooleanRead-only flag
internalBooleanInternal database flag

schemas

Database schemas.

FieldTypeDescription
idBigInt! (PK)Schema OID
nameString! (PK)Schema name
database_idBigInt!References databases.id
database_nameString!Database name
internalBooleanInternal schema flag

tables

Database tables.

FieldTypeDescription
idBigInt! (PK)Table OID
nameString!Table name
database_idBigInt!References databases.id
schema_idBigInt!References schemas.id
estimated_sizeBigIntEstimated row count
column_countIntNumber of columns
index_countIntNumber of indexes
has_primary_keyBooleanWhether a PK exists
temporaryBooleanTemporary table flag

views

Database views.

FieldTypeDescription
idBigInt! (PK)View OID
nameString! (PK)View name
database_idBigInt!References databases.id
schema_idBigInt!References schemas.id
column_countIntNumber of columns
temporaryBooleanTemporary view flag

columns

Table and view columns.

FieldTypeDescription
nameString! (PK)Column name
database_idBigInt!References databases.id
schema_idBigInt!References schemas.id
table_idBigInt!References tables.id or views.id
table_nameString!Parent table/view name
data_typeStringColumn data type
is_nullableBooleanNullable flag
defaultStringDefault value expression
ordinal_positionIntColumn position

constraints

Table constraints (PRIMARY KEY, UNIQUE, FOREIGN KEY, CHECK, NOT NULL).

FieldTypeDescription
nameString! (PK)Constraint name
table_idBigInt!References tables.id
typeStringConstraint type
columns[String!]Constrained column names
references_table_nameStringReferenced table (FK only)
references_columns[String!]Referenced column names (FK only)

extensions

DuckDB extensions (installed and loaded).

FieldTypeDescription
nameString! (PK)Extension name
loadedBooleanWhether currently loaded
installedBooleanWhether installed
install_pathStringInstallation path
descriptionStringExtension description
versionStringExtension version

functions

Registered DuckDB functions.

FieldTypeDescription
nameString! (PK)Function name
database_nameString!Owning database
schema_nameString!Owning schema
typeStringFunction type (scalar, aggregate, table, macro)
return_typeStringReturn type
parameters[String!]Parameter names
parameter_types[String!]Parameter types
has_side_effectsBooleanSide-effect flag

settings

DuckDB configuration settings.

FieldTypeDescription
nameString! (PK)Setting name
valueStringCurrent value
descriptionStringSetting description
input_typeStringExpected input type
scopeStringSetting scope

duckdb_memory

DuckDB memory usage by component.

FieldTypeDescription
tagString! (PK)Memory component tag
memory_usageBigIntMemory usage in bytes
temporary_storageBigIntTemporary storage in bytes

secrets

DuckDB registered secrets (credentials for remote storage).

FieldTypeDescription
nameString! (PK)Secret name
type_nameString!Secret type (references secret_types.type)
providerStringProvider name
persistentBooleanPersisted across restarts
scope[String]Scope patterns

secret_types

Available secret types.

FieldTypeDescription
typeString! (PK)Type identifier
default_providerStringDefault provider
extension_nameStringProviding extension

log_contexts and log_entries

DuckDB logging information (when logging is enabled).

log_contexts:

FieldTypeDescription
idBigInt! (PK)Context ID
scopeString!Log scope
connection_idStringConnection identifier
transaction_idStringTransaction identifier
query_idStringQuery identifier

log_entries:

FieldTypeDescription
context_idBigInt!References log_contexts.id
timestampTimestamp!Entry timestamp
typeStringLog entry type
log_levelStringSeverity level
messageStringLog message text

temporary_files

DuckDB temporary files on disk.

FieldTypeDescription
pathString! (PK)File path
sizeBigIntFile size in bytes

core.cluster Module

The core.cluster module provides cluster management for multi-node deployments. It manages node registration, schema synchronization, and broadcast operations between management and worker nodes.

Tables

nodes

Cluster node registry. Each node registers on startup and updates its heartbeat periodically.

FieldTypeDescription
nameString! (PK)Unique node identifier
urlString!Node IPC endpoint URL
roleString!Node role: management or worker
versionStringBinary version
started_atTimestampNode start time
last_heartbeatTimestampLast heartbeat timestamp
errorStringLast error (null = healthy)

Query Functions

schema_version

Returns the current schema version counter, used for cluster change detection.

{
core_cluster {
schema_version
}
}

Returns: Int!

my_role

Returns this node's cluster role (management or worker).

Returns: String!

management_url

Returns the management node's IPC URL (from the _cluster_nodes table).

Returns: String (null if no management node registered)

Mutation Functions (User-facing)

These mutations are forwarded to the management node if executed on a worker.

FunctionArgumentsDescription
load_sourcename: String!Load/compile data source across the cluster
unload_sourcename: String!Unload data source across the cluster
reload_sourcename: String!Reload data source across the cluster
register_storagetype, name, scope, key, secret, endpoint, use_ssl, url_style, regionRegister object storage secret across the cluster
unregister_storagename: String!Unregister object storage secret across the cluster
invalidate_cachecatalog: StringInvalidate schema cache across the cluster

Internal Mutation Functions

These are broadcast targets used internally between cluster nodes. They require CLUSTER_SECRET authentication.

FunctionArgumentsDescription
handle_source_loadname: String!Worker: attach source without recompile
handle_source_unloadname: String!Worker: detach source
handle_cache_invalidatecatalog: StringHandle cache invalidation broadcast
handle_secret_sync(none)Worker: re-sync secrets from management

core.gis Module

The core.gis module provides geospatial utility functions for converting between geometries and H3 hexagonal cells.

Functions

geom_to_h3_cells

Convert a geometry to a set of H3 cells at the given resolution.

{
core_gis {
geom_to_h3_cells(geom: "POINT(0 0)", resolution: 8, simplify: true, compact: false)
}
}
ArgumentTypeDefaultDescription
geomGeometry!Input geometry
resolutionInt!8H3 resolution level (0-15)
simplifyBooleantrueSimplify geometry before tessellation
compactBooleanfalseCompact the resulting cell set

Returns: [H3Cell!]

h3_cell_to_geom

Convert an H3 cell to its boundary geometry.

ArgumentTypeDescription
cellH3Cell!H3 cell index

Returns: Geometry!

h3_cells_to_multi_polygon

Convert a set of H3 cells to a multi-polygon geometry.

ArgumentTypeDefaultDescription
cells[H3Cell!]!H3 cell indexes
compactBooleanfalseCompact cells before conversion

Returns: Geometry!


core.storage Module

The core.storage module manages object storage registrations (S3, GCS, R2, etc.) for accessing remote files.

Mutation Functions

register_object_storage

Register a new or update an existing object storage with credentials.

ArgumentTypeDefaultDescription
typeString!Storage type (e.g., s3, gcs, r2)
nameString!Storage name
scopeString!Bucket name or sub-path
keyString!Access key ID
secretString!Secret access key
regionString""AWS region
endpointString!Endpoint URL
use_sslBoolean!trueUse HTTPS
url_styleString!URL style: path or vhost
url_compatibilityBooleanfalseURL compatibility mode
kms_key_idString""AWS KMS key for server-side encryption
account_idString""Cloudflare R2 account ID

Returns: OperationResult

unregister_storage

Unregister an existing object storage.

ArgumentTypeDescription
nameString!Storage name to unregister

Returns: OperationResult

Views

registered_object_storages

Currently registered object storages.

FieldTypeDescription
nameString! (PK)Storage name
typeString!Storage type
scope[String]Bucket/path scopes
parametersStringStorage parameters

ls

Directory listing with support for object storages. Reads file contents at the given path.

ArgumentTypeDescription
pathString!Path to list (supports s3://, gcs://, local paths)
FieldTypeDescription
nameString! (PK)File name
contentString!File content

core.info Module

The core.info module provides node information and version details.

Functions

info

Returns detailed information about the current node, including configuration.

{
info {
cluster_mode
node_role
node_name
version
build_date
config {
admin_ui
debug
allow_parallel
max_parallel_queries
max_depth
duckdb { path max_open_conns }
cache { ttl }
}
}
}

Returns: NodeInfo!

NodeInfo fields:

FieldTypeDescription
cluster_modeBoolean!Whether cluster mode is enabled
node_roleString!Node role (management, worker, or standalone)
node_nameString!Node name
versionString!Software version
build_dateString!Build date
configNodeConfig!Engine configuration

NodeConfig fields:

FieldTypeDescription
admin_uiBoolean!Admin UI enabled
debugBoolean!Debug mode
allow_parallelBoolean!Parallel query execution enabled
max_parallel_queriesInt!Maximum concurrent queries
max_depthInt!Maximum query depth
duckdbDuckDBConfig!DuckDB engine configuration
coredbCoreDBConfig!Core database configuration
auth[AuthProviderConfig!]Configured auth providers
cacheCacheConfig!Cache configuration

version

Returns a simplified version object.

{
version {
version
build_date
}
}

Returns: NodeVersion! with fields version: String! and build_date: String!


Logical-Model Introspection (Meta Queries)

A family of meta queries exposes hugr's logical data model (module tree, data objects with relations, functions, data sources) beside the standard __schema/__type introspection. They are resolved on the metadata path — never planned or executed as data queries — and what they return respects the same role-based visibility rules as __schema (hidden elements are absent everywhere, disabled elements stay visible). Unknown names resolve to null, never an error.

They are meta-fields, like __schema and __typename, with the two consequences that follow from it. They are not listed in Query.fields and their result types are not listed in __schema.types, so tooling that reads the schema does not see them (they stay callable, and __type(name:) still resolves the meta-types — that is the capability probe). And they sit outside the role permission rules: a wildcard permission row (type_name: "*", field_name: "*") does not remove logical-model introspection, nor standard __schema introspection, which is governed by the same rule. Only the entry point is exempt — the content is filtered per role as described above, and a disabled role is refused everywhere. See GraphQL API — Logical Model Introspection for usage examples.

Meta Queries

QueryReturnsDescription
_catalog_ModuleThe root module (name: "") — entry point to the whole tree
_module(name: String!)_ModuleModule by full dotted name; "" = root module
_dataObject(name: String!)_DataObjectData object by GraphQL type name; null for non-data-object types
_function(module: String!, name: String!)_FunctionCallable member (function/mutation/subscription); module: "" = root-level functions
_dataSources[_DataSource!]The attached data sources that contribute anything visible to the caller
_dataSource(name: String!)_DataSourceData source by name; null when absent, inactive, or contributing nothing visible
_types(scope: _TypeScope = SOURCE)[__Type!]Logical-model type definitions: SOURCE — residual base types defined by data sources (structs, inputs, enums; excludes data objects, module roots and generated helper types); SYSTEM — engine-defined types. Compiler-derived types belong to neither scope
_search(query: String!, …)_SearchResultRank the logical model by relevance to a natural-language description — modules, data sources, data objects, functions and fields

_search arguments

ArgumentTypeDefaultDescription
queryString!Natural-language description of what you are looking for
kinds[_SearchKind!]allMODULE, DATA_SOURCE, DATA_OBJECT, FUNCTION, FIELD
match_SearchMatchBOTHNAME — substring matching over the name, always available; MEANING — semantic ranking over descriptions; BOTH — name matches first, then meaning, deduplicated
moduleString""Restrict to this module's SUBTREE. A field hit takes the module of the object that owns it. DATA_SOURCE hits ignore it — a source contributes to several modules
objectStringRestrict FIELD hits to one data object
limitInt50Page size, clamped to 1–200
offsetInt0Hits to skip
minScoreFloatDrop MEANING hits scoring below this (0–1). Name-track hits rank on a scale of their own and are never thresholded
includeMcpExcludedBooleantrueInclude fields marked @exclude_mcp — an AI-tooling policy, not an access rule

_SearchResult

FieldTypeDescription
items[_SearchHit!]!The page, ordered by score
limit / offsetInt!The page actually served
hasMoreBoolean!More hits past this page, or candidates left unverified
filteredOutInt!Candidates dropped because the caller may not see them — non-zero distinguishes "nothing matches" from "nothing you may see matches"
lexicalBoolean!true when the MEANING track fell back to substring matching. Always false for match: NAME, where substring matching is the point rather than a fallback
lexicalReasonStringWhy the vector index was unusable; null when it was used

There is deliberately no total: the permission filter runs after ranking, so an honest total would mean scanning the whole index on every query.

_SearchHit

FieldTypeDescription
kind_SearchKind!What the hit is
matchedOn_SearchMatch!Which track found it — NAME or MEANING, never BOTH. Scores are comparable within a track and not across them
nameString!Module: dotted path. Data object: GraphQL type name. Function: field name in its module. Field: field name on its object
moduleNameString!Owning module — required to nest the query; "" for DATA_SOURCE
dataSourceNameStringOwning data source; null for MODULE
descriptionStringCurated description where one exists, the source's otherwise
scoreFloat!0–1, higher is better. Lexical scores are coarse
objectNameStringFIELD only: the data object the field belongs to
typeStringFIELD only: the field's GraphQL type, SDL spelling (String!, [Int])
hugrTypeStringFIELD only: what the field IS — same vocabulary as __Field.hugr_type
refObjectNameStringFIELD only: for a declared @join, the data object it navigates to
module / dataObject / function / dataSourcemeta typesDrill-down through the ordinary _catalog resolvers — exactly one is non-null, matching kind. Costs nothing unless selected
field__FieldFIELD only: the field definition

Name is not meaning. The vector index embeds descriptions, so an identifier never enters it and a semantic search for aw_Product returns what is described in similar words. The NAME track exists for identifiers, costs no embedder, and scores an exact name 1. BOTH concatenates the two — name first — rather than merge-sorting them, because an exact identifier and an embedding distance are not on one scale.

Ranking and its fallback. With an embedder the ranking is semantic, over the annotation vectors the engine seeds and reindex_embeddings refreshes. Without one it falls back to substring matching and reports it (lexical, lexicalReason) — a silent fallback would be indistinguishable from a broken ranking query. Lexical scoring requires every word of the query to appear, so a multi-word query narrows rather than widens.

What a FIELD hit can be. Only four hugrType values reach a hit: column (a stored value), calculated (@sql), function (@function_call or a table-function join) and select (a declared @join, with refObjectName set). Relation navigation fields and @extra_field companions are generated when the GraphQL type is built rather than stored, so they are never search hits.

Permissions. Ranking reads the annotation index with full access — the index lives in the core.catalog.* views, and a role may hold no rights on them — but nothing reaches the caller without passing the same visibility predicates _catalog applies. Search cannot surface anything _dataObject would then refuse to show.

_Module

FieldTypeDescription
nameString!Full dotted module name; empty string for the root module
descriptionStringModule description
longDescriptionStringCurated/summarized long description
dataSources[String!]!Distinct data sources contributing this module's direct members
modules[_Module!]Direct child modules; children with no visible content are omitted
dataObjects[_DataObject!]Member data objects (root: objects without @module)
functions[_Function!]All callable members, including subscriptions
queryType / mutationType / subscriptionType / functionType / mutationFunctionType__TypeThe module's generated root types (root module: Query/Mutation/Subscription/Function/MutationFunction); null when absent

_DataSource

FieldTypeDescription
nameString!Data source name (the @catalog name)
engineStringThe source's engine type string
description / longDescriptionStringDescriptions
readOnlyBoolean!Mutations are not generated for this source
asModuleBoolean!The source is exposed as a module of its own
isExtensionBoolean!The source extends other sources' objects
modules[String!]!Modules this source places members in; "" is the root module

_DataObject

FieldTypeDescription
nameString!GraphQL type name (source-prefixed, globally unique)
type_DataObjectType!TABLE or VIEW
properties_DataObjectProperties!Extensible flag bag: isCube, isM2M, isHypertable, softDelete, hasVectors
description / longDescriptionStringDescriptions
moduleName / moduleString! / _ModuleOwning module (name / back-reference)
primaryKey[String!]!@pk field names; empty when none
args[__InputValue!]Parameterized-view arguments; null when not parameterized
fields[__Field!]Fields (permission-filtered, same rules as __Type.fields)
relations[_Relation!]Logical edges to other data objects, both directions
dataSourceNameString!Owning data source
dataSources[String!]!Owner plus sources that contributed extension fields

_Relation

FieldTypeDescription
nameString!Relation name (@references(name:)) or the join field name
direction_RelationDirection!FORWARD (viewed object is the source) or BACK (it is the destination)
kind_RelationKind!FK, M2M, or JOIN (JOIN is one-directional, always FORWARD)
fieldNameStringThe field on the viewed object materializing the edge
descriptionStringPer-endpoint description
dataObject_DataObjectThe far object (M2M: the far leg, not the junction)
through_DataObjectM2M junction; null otherwise
sourceKeys / destinationKeys[String!]!Key field mappings in canonical source→destination orientation
dataSourceStringDeclaring data source (cross-source edges visible)

Relation SQL (@join(sql:) and similar) is never exposed.

_Function

FieldTypeDescription
nameString!Field name on the module's function root type
type_FunctionType!FUNCTION, MUTATION, or SUBSCRIPTION
description / longDescriptionStringDescriptions
moduleName / moduleString! / _ModuleOwning module
args[__InputValue!]Client-facing arguments (@arg_default server-injected arguments excluded)
returns__TypeReturn type
isTableBoolean!true when the function returns a row set
dataSourceNameStringOwning data source

Enums

EnumValues
_TypeScopeSOURCE, SYSTEM
_DataObjectTypeTABLE, VIEW
_FunctionTypeFUNCTION, MUTATION, SUBSCRIPTION
_RelationDirectionFORWARD, BACK
_RelationKindFK, M2M, JOIN

All meta-types resolve through standard introspection (__type(name: "_Module")), and the meta root queries are ordinary system fields of Query (single-underscore names, like _join and jq) visible in __schema output — GraphiQL autocomplete and code generators work with them out of the box. GraphQL reserves double-underscore names for the built-in introspection system, which is why the family uses a single underscore.


Catalog Views

The logical model is also queryable as plain rows: the core.catalog module publishes views over the CoreDB catalog schema, written on every catalog load/reload. They are the SQL half of the logical model (the _catalog meta queries are the GraphQL half). The views are hosted on the core data source, so they execute entirely inside the CoreDB engine — full pushdown on a PostgreSQL CoreDB, ready for pgvector/HNSW-backed semantic search.

ViewContent
core.catalog.modulesModule tree nodes (name, parent, effective description) — only modules with at least one active data source
core.catalog.module_data_sourcesModule → contributing data sources, as a closure over submodules
core.catalog.active_sourcesData sources with their runtime state; configuration joined in when present
core.catalog.stored_catalogsRegistered catalog (schema definition) sources
core.catalog.catalog_dependenciesDeclared dependency edges between stored catalogs
core.catalog.data_objectsTables/views: name, data source, module, kind, parsed properties
core.catalog.fieldsData-object fields: type, properties, attribution, is_pk, ordinal — including declared @join / @function_call fields
core.catalog.relationsONE row per logical @references edge (fk / m2m), keyed (source, name), with both generated nav fields (source_field / destination_field) and key mappings
core.catalog.functionsFunctions, mutations and subscriptions with structured args
core.catalog.typesResidual source-defined types as raw SDL
core.catalog.annotationsThe curation overlay: descriptions, audit fields, the embedding vector — including orphans (curation of currently unloaded entities) and load-time seed rows

The views apply no row-level permission filtering — they are an administrative surface. Access is governed by the ordinary data-object permission rules applied to the views themselves (grant, hide or disable core.catalog.* per role exactly like any other data object); request-scoped, permission-filtered catalog introspection is exclusively the job of the _catalog meta queries (_search included). The views' only built-in filter is the data-source state semi-join: entities of unloaded, disabled or suspended data sources are hidden (their rows stay in storage — unloading is a flag flip, and loading an unchanged source back is instant; rows are physically deleted only when a source is unregistered). Effective descriptions COALESCE the annotations overlay over the source-provided text; raw SQL (view definitions, computed-field expressions, join conditions, default expressions, function SQL) is never projected. When an embedder is configured the views project the annotation-joined vec and carry @embeddings — semantic search pushes down into the CoreDB engine (pgvector/HNSW on PostgreSQL), and the engine seeds vector-only annotation rows from the source-schema descriptions during every load, so a just-connected source is semantically searchable immediately; curation and summarization refine on top and always win. Relation-generated navigation fields are curated as ordinary field annotations keyed by the owning object and the field name (source.source_field / destination.destination_field — set with annotate_field); core.catalog.relations projects the curated text in its *_field_description columns.

Upgrading from v0.3.42

v0.3.42 published these views under the core module as core.entity_* (GraphQL types core_entity_modules, core_entity_fields, …). The move is entirely in the served schema — CoreDB data and its schema version are untouched, so no migration runs — and that cuts both ways: stored strings naming the old types are not rewritten. A role_permissions row naming core_entity_* matches nothing after the upgrade, and access is allow-by-default, so a deny written against the old names silently stops applying. Curated annotations keyed to the old type names become orphan rows and their text drops out of the served surface and the search index. If you created either against core.entity_*, re-create them against the new names.


Schema Management Functions

These mutation functions manage schema metadata in the core database. They are used by the AI summarizer and administrative tools.

Curation Functions

Descriptions are curated through the mutation functions of the core.catalog module. Writes land in the annotations overlay (catalog.annotations) — storage the data-source load/unload/reload machinery never touches — so curated descriptions survive unload and reload by construction. When an embedder is configured, the embedding vector is recomputed on every write.

An empty description clears the curation: the source-provided (generated) text shows through again.

mutation {
function { core { catalog {
annotate_data_object(
name: "customers"
description: "CRM customers"
long_description: ""
) { success }
} } }
}

Curation has two surfaces. Prefer the logical one — a curated logical entity also shows through on everything generation derives from it (its filter, aggregation and mutation-input fields):

FunctionArguments
annotate_modulename, description, long_description
annotate_data_sourcename, description, long_description
annotate_data_objectname, description, long_description
annotate_fieldtype_name, name, description, long_description — also covers relation navigation fields
annotate_typename (a source-declared struct or input type), description, long_description
annotate_functionmodule ("" = root), name, kind ("function" | "mutation" | "subscription", default "function"), description, long_description

The generated GraphQL surface is reachable only where a single generated type, field or argument has no logical entity to key on:

FunctionArguments
annotate_gql_typename, description, long_description
annotate_gql_fieldtype_name, name, description, long_description
annotate_gql_argumenttype_name, field_name, name, description, long_description

Summarization progress is tracked by the summarizer tool itself — the engine stores the curated text and its embedding only.

Catalog Maintenance Functions

FunctionArgumentsDescription
remove_data_source_schemaname: String!Delete a data source's stored schema entirely; curation is kept. Rejected while the source is still loaded — unload it first.
reset_data_source_versionname: String!Reset the stored schema version so the next load re-reads the source and rewrites its schema instead of reusing the stored one.
reindex_embeddingsname: String = "", batch_size: Int = 50Recompute embedding vectors; empty name means every entity. Requires a configured embedder.

_schema_reset_summarized was removed — what to re-summarize is a summarizer-side decision now.

The older _schema_* names survive only as the internal DuckDB UDFs these fields are bound to; they are no longer part of the GraphQL surface.


Core DB Tables (DDL)

These are the underlying SQL tables in the core database that back the system. They are managed automatically by the engine and should not be modified directly.

The catalog namespace — logical model storage

A data source's schema is stored as a logical model in the catalog schema; the served GraphQL surface (filters, aggregations, mutation inputs, navigation fields, module roots) is generated from these rows on read. There is no compiled-schema table.

Property bags are typed STRUCT columns on a DuckDB CoreDB and JSONB on PostgreSQL — the writer sends the same JSON text to both. Raw SQL that the engine executes (view definitions, computed-field expressions, join conditions, function bodies) lives in those bags and is never projected by the core.catalog.* views.

TablePrimary keyContent
catalog.data_source_metadata_sourcePer-source load state: content-hash version, engine, prefix, as_module, read_only, is_extension, and the flags loaded / disabled / suspended. Unloading is a flag flip — rows stay, so reloading an unchanged source is instant. A pseudo-row _embedder fingerprints the embedder configuration.
catalog.modulesnameModule tree; parent is derived from the dotted name at write time.
catalog.module_data_sourcesmodule, data_sourceModule → contributing source closure, with has_* flags recording which root kinds (query, mutation, function, mutation function, subscription) the source contributes. Module visibility is a plain semi-join against data_source_meta.
catalog.data_objectsnameTables/views/cubes: prefixed GraphQL name, original_name, data_source, module, kind, property bag.
catalog.fieldstype_name, nameData-object fields, including declared @join / @function_call fields, with ordinal, deprecation_reason and a property bag. Struct and input types live in catalog.types as SDL instead.
catalog.relationssource, nameOne row per logical @references edge (fk | m2m), readable from both sides: destination, m2m_object, key mappings, and the generated navigation field names.
catalog.functionsmodule, name, kindFunctions, mutation functions and subscriptions. kind is part of the identity — the same name may exist in more than one root namespace.
catalog.typesnameResidual source-defined base types (structs, inputs, enums) kept as raw SDL.
catalog.annotationsentity_kind, entity_keyThe curation overlay: description, long_description, audit columns and the embedding vec. Load/unload/reload never touch it, so curated text survives by construction; orphan rows (curation of an unloaded entity) are legal, and rows with a vector but no text are load-time seeds.
catalog.data_source_dependenciesdata_source, depends_onDeclared cross-source dependency edges.

On PostgreSQL the vector extension is created and catalog.annotations.vec gets an HNSW cosine index; on DuckDB the vector is a FLOAT[N] array.

Removed in CoreDB 0.0.20

The eleven compiled-schema tables — _schema_catalogs, _schema_types, _schema_fields, _schema_arguments, _schema_enum_values, _schema_directives, _schema_modules, _schema_data_objects, _schema_data_object_queries, _schema_catalog_dependencies and _schema_module_type_catalogs — were dropped. _schema_settings is not one of them: it survives and still holds the schema_version counter.

An existing database must be migrated before an engine of this version will start — see CoreDB version and migrations.

_schema_settings

Key-value settings store (includes schema_version counter and config).

CREATE TABLE _schema_settings (
key VARCHAR NOT NULL PRIMARY KEY,
value JSON NOT NULL
);

_cluster_nodes

Cluster node registry for multi-node deployments.

CREATE TABLE _cluster_nodes (
name VARCHAR NOT NULL PRIMARY KEY,
url VARCHAR NOT NULL,
role VARCHAR NOT NULL,
version VARCHAR,
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_heartbeat TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
error VARCHAR
);

CoreDB version and migrations

The core database carries its own version in a one-row version table. The current version is 0.0.20, and the engine compares it for equality at startup — a database at any other version is refused, in either direction. An engine upgrade therefore requires migrating the core database first.

A new database is created at the current version directly, so a fresh install needs no migration step.

For an existing database:

  • The ghcr.io/hugr-lab/automigrate image applies pending migrations on startup — the recommended path, and the reason most deployments never run a migration by hand.
  • The standalone migrate binary from the hugr repository does the same job out of band: migrate -core-db <path-or-postgres-url> -path ./migrations.

Migrations support both CoreDB backends (embedded DuckDB and PostgreSQL). Back the core database up first — it holds curation, permissions and API keys, none of which can be regenerated from a data source.