SQL REPL

bewitch repl connects to the running daemon and opens an interactive DuckDB SQL console. The REPL uses readline for line editing with full multi-line support — arrow up/down between lines, edit earlier lines, and the input area auto-resizes.

launch
bewitch repl

# or connect remotely
bewitch -addr myserver:9119 -token secret repl

SQL Queries

SQL statements are terminated with ;. Until a semicolon is entered, pressing Enter adds a new line (the prompt changes to ...>). Tab triggers context-aware completion using DuckDB's built-in sql_auto_complete().

example query
bewitch> SELECT d.value AS mount,
    ...>   AVG(m.used_bytes * 100.0 / m.total_bytes) AS pct
    ...> FROM disk_metrics m
    ...> JOIN dimension_values d ON d.id = m.mount_id
    ...> WHERE m.ts > now() - INTERVAL '1 hour'
    ...> GROUP BY d.value;
 mount | pct
-------+------
 /     | 62.34
 /home | 41.17
(2 rows)

Only read-only queries are allowed — SELECT, EXPLAIN, and PRAGMA. Write/DDL statements are rejected server-side using DuckDB's statement parser (not keyword matching), so bypass attempts likeWITH cte AS (...) INSERT INTO ... are caught.

Key Bindings

KeyAction
TabAutocomplete (SQL keywords, table names, dot-commands)
Ctrl+DExit
Ctrl+CCancel current input
Ctrl+RReverse search history
Alt+P / Alt+NNavigate history (previous / next)

Dot-Commands

CommandDescription
.metricsMetric tables with row counts and time ranges
.tablesList all tables with row counts
.schema [table]Show column definitions
.count [table]Row counts with time ranges
.dimensionsDimension lookup values (mounts, sensors, interfaces, zones)
.export <table> <path>Export table to file
.export (<sql>) <path>Export query results to file
.helpShow available commands and examples
.quitExit

Data Export

Export data to CSV, Parquet (zstd compressed), or JSON. Format is inferred from the file extension.

export examples
bewitch> .export all_cpu_metrics /tmp/cpu.csv
Exported 123456 rows to /tmp/cpu.csv

bewitch> .export (SELECT * FROM all_cpu_metrics
    ...> WHERE ts > now() - INTERVAL '1 hour') /tmp/recent.parquet
Exported 720 rows to /tmp/recent.parquet

Dimension Tables

Metric tables use normalized dimension IDs for mount names, interfaces, sensors, and zones. Use .dimensions to see the mapping, or JOIN with dimension_values:

dimension join
SELECT d.value AS interface, n.rx_bytes_sec, n.tx_bytes_sec
FROM network_metrics n
JOIN dimension_values d ON d.category = 'interface' AND d.id = n.interface_id
WHERE n.ts > now() - INTERVAL '10 minutes';

Scripting

Piped input works for non-interactive use:

echo "SELECT COUNT(*) FROM cpu_metrics;" | bewitch repl

# multi-line
cat <<'SQL' | bewitch repl
SELECT d.value AS mount, COUNT(*) as samples
FROM disk_metrics m
JOIN dimension_values d ON d.id = m.mount_id
GROUP BY d.value;
SQL

History

Command history is saved to ~/.bewitch_sql_history and persists across sessions.