Skip to content

Docs: make yardstick's functions discoverable from duckdb_functions() #51

Description

@rustyconover

Hi! I'm working on helping AI agents and tools discover and correctly use DuckDB community extensions. There are 346 in the catalog and agents mostly can't find them.

This will be a multi-step effort – types, tables and other catalog objects need the same treatment – but functions are by far the biggest surface, so that's where I'm starting.

The reason is that an agent connected to a database can only learn what an extension does by querying duckdb_functions(). Your README and the extended_description in community-extensions aren't reachable from a SQL connection, and are usually too large to fit in an agent's context anyway. Per-function metadata is – it's searchable one function at a time.

Here's what yardstick exposes there today (1 table):

In duckdb_functions() yardstick
Functions registered 1
…with a description 0 (0.0%)
…with an examples entry 0 (0.0%)
…with real parameter names, not col0 0 / 1 (0.0%)

Catalog-wide that description figure is 29.6%, so this is an ecosystem gap rather than anything specific to yardstick. It's mostly an API-shape problem: RegisterFunction(ScalarFunction), the overload nearly everyone uses, has nowhere to put a description.

The fix

// before
loader.RegisterFunction(yardstick_function);

// after
CreateTableFunctionInfo info(yardstick_function);
FunctionDescription desc;
desc.parameter_names = {"arg1"};
desc.description     = "…one sentence on what yardstick does…";
desc.examples        = {"SELECT * FROM yardstick(…);"};
desc.categories      = {""};
info.descriptions.push_back(desc);
loader.RegisterFunction(std::move(info));

CreateScalarFunctionInfo, CreateAggregateFunctionInfo and CreateTableFunctionInfo all work the same way. The definitions, if it's easier to read them directly: FunctionDescription and the RegisterFunction overloads.

These numbers are from the 1.5.x line (1.5.5). I know a lot of you are getting ready for 2.0 – FunctionDescription and these overloads are unchanged there, so this can fold into that work rather than be a separate task.

If you only do one thing, do parameter names – they turn f(col0, col1) into a signature a caller can reason about.

This is also a good task to hand to a coding agent. The change is mechanical and repetitive, and an agent with your source in context can usually convert every registration in one pass.

A prompt that works
In this DuckDB extension, functions are registered with the bare
loader.RegisterFunction(<fn>) overload, which cannot carry documentation.

Convert each registration to the matching CreateScalarFunctionInfo,
CreateAggregateFunctionInfo or CreateTableFunctionInfo form and attach a
FunctionDescription with:

  - parameter_names: the real argument names, never col0/col1
  - description:     one sentence on what the function does
  - examples:        one runnable call. A bare expression for scalar and
                     aggregate functions; a full "SELECT * FROM f(...)"
                     statement for table functions, since a table function
                     used as a bare expression is a binder error.
  - categories:      a short tag or two

Also set info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT, because
that is what the bare RegisterFunction overload does internally and the
default on CreateInfo is ERROR_ON_CONFLICT.

Infer each description from the implementation and any existing README or
docs. Do not invent behaviour you cannot verify from the source - leave a
TODO instead.
A note on examples formatting

Core DuckDB writes scalar and aggregate examples as a bare expression – date_trunc('hour', TIMESTAMPTZ '1992-09-20 20:38:40') – and all 2,076 documented built-ins follow that. Table functions need a full statement (SELECT * FROM my_func(…)), since using one as a bare expression is a binder error. spatial uses full statements throughout with the result as a trailing comment, which is the most useful form for an agent.

The 1 function with no description:

table        yardstick(col0)

The 1 function with placeholder parameter names:

yardstick(col0)

Done well elsewhere

Extension Coverage Source
spatial 268/280 described, 270 with examples duckdb/duckdb-spatial
stochastic 444/444 described, all with examples query-farm/stochastic
anofox_tabular 157/159 described, 99% real parameter names DataZooDE/anofox-tabular
inflector 30/30 described, with categories query-farm/inflector

From loading all 346 community extensions against DuckDB 1.5.5 and reading duckdb_functions().

– Rusty, Query.Farm

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions