@@ -168,122 +168,166 @@ def close(self) -> None:
168168 self ._output_file_handle .close ()
169169
170170
171+ _CLI_EPILOG = """
172+ \b
173+ EXAMPLES:
174+ # Table function (generates data, no input)
175+ vgi-client --function sequence --args '[10]'
176+ \b
177+ # Table-in-out function (transforms input)
178+ vgi-client --input data.parquet --function echo
179+ \b
180+ # Scalar function (per-row, single output column)
181+ vgi-client --input in.parquet --function upper_case -t scalar
182+ \b
183+ # Output to file with format
184+ vgi-client --function sequence --args '[5]' -o out.json
185+ vgi-client --function sequence --args '[5]' -o out.parquet -f parquet
186+ vgi-client --function sequence --args '[5]' -o - -f arrow-ipc
187+ \b
188+ # Catalog operations
189+ vgi-client catalog list -s vgi-example-worker
190+ vgi-client catalog attach mydb -s vgi-example-worker
191+
192+ \b
193+ FUNCTION TYPES:
194+ table No input, generates data (sequence, range)
195+ table-in-out Transforms input (echo, filter) - default with --input
196+ scalar Per-row transform, single column output (upper_case)
197+ auto Default: table-in-out if --input, else table
198+
199+ \b
200+ ARGUMENT FORMAT (--args as JSON array):
201+ '[]' No arguments
202+ '[10]' Single integer
203+ '["name"]' Single string (column name)
204+ '[0, 100, 5]' Multiple integers
205+ '[true, 3.14]' Mixed types
206+
207+ \b
208+ OUTPUT FORMATS (-f/--format):
209+ json JSON Lines, one object per row (default)
210+ csv CSV with header row
211+ parquet Apache Parquet columnar format
212+ arrow-ipc Arrow IPC stream (for debugging/piping)
213+
214+ \b
215+ ENVIRONMENT VARIABLES:
216+ VGI_IPC_DEBUG=1 Trace IPC read/write (protocol debug)
217+ VGI_IPC_STATS=1 Log IPC statistics per invocation
218+ VGI_QUIET=1 Suppress worker startup logging
219+ """
220+
221+
171222def _create_cli () -> Any :
172223 """Create the CLI command group. Separated for testability."""
173224 import click
174225 import pyarrow .parquet as pq
175226
176227 from vgi .client .cli_catalog import catalog
177228
178- @click .group (invoke_without_command = True )
229+ @click .group (invoke_without_command = True , epilog = _CLI_EPILOG )
179230 @click .option (
180231 "--input" ,
181232 "input_file" ,
182233 required = False ,
183- # This validates the that file exists.
184234 type = click .Path (exists = True ),
185- help = "Path to input parquet file (omit for table functions without input)" ,
235+ help = (
236+ "Input parquet file path. Required for table-in-out and scalar functions. "
237+ "Omit for table functions (generators)."
238+ ),
186239 )
187240 @click .option (
188241 "--output" ,
242+ "-o" ,
189243 "output_file" ,
190244 type = str ,
191- help = "Path to output file (use - for stdout) " ,
245+ help = "Output file path. Use '-' for stdout. If omitted, outputs to log. " ,
192246 )
193247 @click .option (
194248 "--format" ,
249+ "-f" ,
195250 "output_format" ,
196251 type = click .Choice (["json" , "csv" , "parquet" , "arrow-ipc" ]),
197252 default = "json" ,
198- help = (
199- "Output format (default: json). Use 'arrow-ipc' for Apache Arrow IPC "
200- "streaming format, which is useful for debugging or piping to other "
201- "Arrow-aware tools."
202- ),
253+ help = "Output format: json (default), csv, parquet, or arrow-ipc." ,
203254 )
204255 @click .option (
205256 "--function" ,
206257 "function_name" ,
207258 required = False ,
208259 type = str ,
209- help = "Name of the function to run (e.g., echo, sum_all_columns, repeat_inputs) " ,
260+ help = "Function name to invoke (e.g., sequence, echo, upper_case). " ,
210261 )
211262 @click .option (
212263 "--args" ,
213264 "arguments" ,
214265 default = "[]" ,
215266 type = str ,
216- help = "JSON array of arguments to pass to the function (default: []) " ,
267+ help = "JSON array of positional arguments. Example: '[10]' or '[ \" col \" ]'. " ,
217268 )
218269 @click .option (
219270 "--server" ,
271+ "-s" ,
220272 "server_path" ,
221273 default = "vgi-example-worker" ,
222274 type = str ,
223- help = "Path to the VGI worker" ,
275+ help = "VGI worker command or path. Default: vgi-example-worker." ,
276+ )
277+ @click .option (
278+ "--type" ,
279+ "-t" ,
280+ "function_type" ,
281+ type = click .Choice (["auto" , "table" , "table-in-out" , "scalar" ]),
282+ default = "auto" ,
283+ help = (
284+ "Function type: auto (default), table, table-in-out, or scalar. "
285+ "'auto' uses table-in-out if --input provided, otherwise table."
286+ ),
224287 )
225288 @click .option (
226289 "--worker-stderr" ,
227- "worker_stderr" ,
228290 is_flag = True ,
229291 default = False ,
230- help = "Pass worker stderr through to CLI stderr" ,
231- )
232- @click .option (
233- "--projection-id" ,
234- "projection_ids" ,
235- multiple = True ,
236- type = int ,
237- help = "Projection column ID (can be specified multiple times)" ,
292+ help = "Pass worker stderr through to CLI stderr (for debugging)." ,
238293 )
239294 @click .option (
240295 "--max-workers" ,
241296 "max_workers" ,
242297 type = int ,
243298 default = None ,
244- help = "Maximum number of worker processes (clamps function's max_processes)" ,
299+ help = "Max worker processes. Clamps function's max_processes setting." ,
300+ )
301+ @click .option (
302+ "--projection-id" ,
303+ "projection_ids" ,
304+ multiple = True ,
305+ type = int ,
306+ help = "Column ID for projection pushdown. Can be repeated." ,
245307 )
246308 @click .option (
247309 "--table-input-position" ,
248310 "table_input_position" ,
249311 type = int ,
250312 default = None ,
251313 help = (
252- "Position in positional arguments where table input should be inserted "
253- "(0-indexed). If not specified, table input is not included in positional "
254- "args. E.g., --args '[\" prefix\" ]' --table-input-position 1 inserts "
255- 'table input at position 1, resulting in ("prefix", TABLE_INPUT).'
314+ "Position (0-indexed) to insert table input in positional args. "
315+ "Example: --args '[\" prefix\" ]' --table-input-position 1"
256316 ),
257317 )
258318 @click .option (
259319 "--attach-id" ,
260320 "attach_id" ,
261321 type = str ,
262322 default = None ,
263- help = (
264- "Unique identifier for the DuckDB database attachment as a hex string. "
265- "Used to trace calls back to a specific attachment."
266- ),
267- )
268- @click .option (
269- "--type" ,
270- "function_type" ,
271- type = click .Choice (["auto" , "table" , "table-in-out" , "scalar" ]),
272- default = "auto" ,
273- help = (
274- "Function type. 'auto' (default) uses table-in-out if --input is provided, "
275- "otherwise table. Use 'scalar' for scalar functions."
276- ),
323+ help = "DuckDB attachment ID (hex string) for catalog context." ,
277324 )
278325 @click .option (
279326 "--transaction-id" ,
280327 "transaction_id" ,
281328 type = str ,
282329 default = None ,
283- help = (
284- "Unique identifier for the DuckDB transaction as a hex string. "
285- "Allows functions to participate in transactional semantics."
286- ),
330+ help = "DuckDB transaction ID (hex string) for transactional operations." ,
287331 )
288332 @click .pass_context
289333 def cli (
@@ -302,11 +346,10 @@ def cli(
302346 function_type : str ,
303347 transaction_id : str | None ,
304348 ) -> None :
305- """VGI client for function invocation and catalog management.
306-
307- When called without a subcommand and with --function, invokes a VGI function.
308- Use subcommands (catalog, schema, table, view, transaction) for catalog ops.
349+ """VGI client - invoke functions and manage catalogs.
309350
351+ QUICK START: Use --function to invoke a VGI function, or use the
352+ 'catalog' subcommand for catalog operations. See examples below.
310353 """
311354 # If a subcommand is being invoked, skip function invocation
312355 if ctx .invoked_subcommand is not None :
0 commit comments