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:
The 1 function with placeholder parameter names:
Done well elsewhere
From loading all 346 community extensions against DuckDB 1.5.5 and reading duckdb_functions().
– Rusty, Query.Farm
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 theextended_descriptionin 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
yardstickexposes there today (1 table):duckdb_functions()descriptionexamplesentrycol0Catalog-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
CreateScalarFunctionInfo,CreateAggregateFunctionInfoandCreateTableFunctionInfoall work the same way. The definitions, if it's easier to read them directly:FunctionDescriptionand theRegisterFunctionoverloads.These numbers are from the 1.5.x line (1.5.5). I know a lot of you are getting ready for 2.0 –
FunctionDescriptionand 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
A note on
examplesformattingCore 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.spatialuses 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:The 1 function with placeholder parameter names:
Done well elsewhere
spatialstochasticanofox_tabularinflectorFrom loading all 346 community extensions against DuckDB 1.5.5 and reading
duckdb_functions().– Rusty, Query.Farm