JavaScript runtime API available to minitrace JS command handlers
JavaScript command handlers run in a Goja-powered JS runtime with access to DuckDB through the minitrace module, the Goja NodeJS stdlib, and several other built-in modules. This page is a complete reference for what each module exposes.
The minitrace module is the primary API for querying and working with the loaded DuckDB session table.
const mt = require("minitrace");
Executes a read-only SQL query against the loaded DuckDB table and returns all rows as an array of objects. Arguments are flattened and passed as query parameters.
const rows = mt.query(`
SELECT id, title, environment->>'agent_framework' AS framework
FROM ${mt.tableName}
WHERE (timing->>'started_at') > '2026-01-01'
LIMIT 100
`);
mt.tableName.Array<Record<string, any>> — one map per row.SELECT and read-only functions are allowed).mt.queryOne() for single-row queries.Same as mt.query(), but returns only the first row or null if the result set is empty.
const session = mt.queryOne(`
SELECT * FROM ${mt.tableName}
WHERE id =
`, sessionId);
Record<string, any> | nullThe name of the DuckDB table the archive was loaded into. Use this in SQL FROM clauses inside template literals — never hardcode a table name.
`FROM ${mt.tableName} WHERE ...`
stringWhen your SQL uses DuckDB JSON arrow operators inside predicates, parenthesize the extraction. DuckDB gives -> / ->> low precedence, so a parenthesized predicate like (timing->>'started_at') > '2026-01-01' is safer and easier to read than relying on implicit grouping.
A collection of helper functions that generate safely escaped SQL literals. Always use these when user-supplied values become part of predicates; never concatenate raw strings.
Returns a single-quoted, single-quote-escaped SQL string literal.
mt.sql.string("O'Reilly") // => "'O''Reilly'"
stringstring — a single-quoted SQL literalReturns a comma-separated, single-quoted list of SQL string literals. Handles string[], Array<any>, and bare string (returns a single quoted string).
mt.sql.stringIn(["codex", "pi"]) // => "'codex', 'pi'"
mt.sql.stringIn("codex") // => "'codex'"
string | string[] | any[]string — a comma-separated, single-quoted listReturns a LIKE pattern with % wildcards on both sides. Handles single-quote escaping.
mt.sql.like("tool fail") // => "'%tool fail%'"
stringstring — a single-quoted LIKE patternA read-only object with information about the current command invocation context.
| Property | Type | Description |
|---|---|---|
mt.runtime.tableName | string | Same as mt.tableName |
mt.runtime.dbPath | string | Path to the loaded DuckDB database |
mt.runtime.archiveGlob | string[] | Archive glob patterns used |
mt.runtime.persistLoaded | boolean | Whether the table was persisted |
mt.runtime.commandName | string | The current command name |
if (mt.runtime.persistLoaded) {
// use persisted table hints
}
The NodeJS timer module for scheduling and async control.
const { setTimeout, setInterval, clearInterval } = require("timer");
setTimeout(fn, ms) — run fn after ms millisecondssetInterval(fn, ms) — run fn every ms milliseconds; returns an interval IDclearInterval(id) — cancel an interval// Async command using the timer module
function slowAnalysis(filters) {
return new Promise((resolve) => {
setTimeout(() => {
const mt = require("minitrace");
resolve(mt.query(`SELECT COUNT(*) AS n FROM ${mt.tableName}`));
}, 1000);
});
}
DuckDB access from go-go-goja. Registered in the default module set.
const db = require("database");
Provides direct DuckDB connection access. For most use cases mt.query() is simpler; use database when you need connection-level control or transactions.
The NodeJS fs module for file system operations.
const fs = require("fs");
fs.readFileSync(path) — read a file as a stringfs.readFile(path, callback) — async readfs.writeFileSync(path, data) — write a string to a filefs.statSync(path) — get file statsRun external shell commands.
const { execSync, exec } = require("exec");
execSync(cmd) — run a command synchronously, return stdoutexec(cmd, callback) — run a command asynchronouslyThe NodeJS path module for path manipulation.
const path = require("path");
path.join(...parts)path.basename(p), path.dirname(p), path.extname(p)path.resolve(...parts)The NodeJS console module. Logs go to the server log or CLI output.
const console = require("console");
console.log("debug info:", someValue);
These modules are registered by go-go-goja's default registry but are less commonly needed in command handlers:
| Module | Contents |
|---|---|
buffer | NodeJS Buffer API (Buffer.from(...), etc.) |
events | NodeJS EventEmitter (new events.EventEmitter()) |
os | NodeJS os module (os.EOL, os.platform(), etc.) |
assert | NodeJS assertion library |
util | NodeJS utilities (util.inspect(...), util.format(...)) |
url | NodeJS URL parser |
querystring | NodeJS query string utilities |
JS command files can require() sibling or relative helper modules. Those files are resolved relative to the command file location.
// overview/helpers.js — relative helper module
function classifyFramework(framework) {
if (framework === "codex") return "Codex";
if (framework === "pi") return "Pi";
return "Other";
}
module.exports = { classifyFramework };
// overview/session-analysis.js — consuming the helper
const { classifyFramework } = require("./helpers");
JS command handlers can declare an output mode in __verb__:
--output json, --output csv, etc.).query commands): Returning plain strings or unstructured data is deferred. Do not rely on text-mode output in go-minitrace query commands yet.__verb__("myCommand", {
name: "my-command",
short: "My command",
output: "glaze", // default — row-shaped data
});
Update (v0.4+): NormalizeValue() now converts *big.Int (DuckDB SUM over integers) to int64 and duckdb.Decimal to float64 before values reach Goja. This eliminates the BigInt/Number mixing error for all query results. No Number() wrapping is needed in JS command handlers.
If you are running an older version (pre-v0.4), or if you construct *big.Int values in Go code that flows into Goja, you may still hit the error:
TypeError: Cannot mix BigInt and other types, use explicit conversions
In that case, wrap values in Number() before using them in arithmetic, comparisons, or string interpolation:
// Pre-v0.4 workaround: wrap aggregates in Number()
const total = Number(r.total_calls);
const success = Number(r.success_count);
const rate = total > 0 ? (success / total * 100).toFixed(1) + "%" : "N/A";
The underlying type mapping:
| DuckDB expression | Go type | Goja JS type |
|---|---|---|
COUNT(*) | int64 | number |
SUM(integer) | *big.Int → int64 | number (since v0.4) |
AVG() | float64 | number |
MIN/MAX | int32 | number |
SUM(double) | float64 | number |
DECIMAL / NUMERIC | duckdb.Decimal → float64 | number (since v0.4) |
Every mt.query() and mt.queryOne() call is validated before execution. Only SELECT statements and read-only functions are allowed. Any write operation (INSERT, UPDATE, DELETE, COPY, etc.) will be rejected with an error.
These static markers are scanned by go-minitrace at load time to build the CLI command surface. They must appear at the top level of the JS file and cannot be inside functions.
Declares a CLI-executable command verb.
__verb__("sessionList", {
name: "session-list", // CLI command name (required)
short: "List sessions", // Short help text (required)
long: "Optional longer help text",
output: "glaze", // Output mode: "glaze" or "text"
fields: { // Bind flag sections
filters: { bind: "filters" }
},
tags: ["overview", "sessions"],
metadata: { // Free-form metadata
since: "1.2.0"
}
});
Declares a named form section for grouping fields in the CLI flag schema and web UI form.
__section__("filters", {
title: "Filters",
fields: {
framework: {
type: "stringList",
default: [],
help: "Filter by agent framework",
},
limit: {
type: "int",
default: 25,
help: "Maximum number of rows",
},
},
});
Package-level metadata for the file.
__package__("session-tools", {
short: "Session analysis tools",
long: "Set of commands for analyzing minitrace sessions",
});
Fields declared in __section__ use Glazed field definitions. The following types are fully supported in both CLI and web UI:
| Type | CLI flag example | Notes |
|---|---|---|
string | --my-field value | |
bool | --my-field | Defaults to false when optional |
int | --my-field 42 | |
float | --my-field 3.14 | |
date | --my-field 2026-01-01 | ISO 8601 date |
choice | --my-field opt1 | Restricted to defined choices |
stringList | --my-field a,b,c | Comma-separated values |
intList | --my-field 1,2,3 | Comma-separated integers |
floatList | --my-field 1.0,2.5 | Comma-separated floats |
choiceList | --my-field opt1,opt2 | Multiple restricted choices |
Types outside this set may work on the CLI but the web form will not render them correctly yet.
go-minitrace help structured-query-commands — authoring guide: scanner markers, file-to-CLI path convention, repository layout, aliasesgo-minitrace help analysis-guide — end-to-end workflow covering when to use JS vs SQL and the full authoring loopgo-minitrace help writing-duckdb-queries — SQL patterns for the sessions_base schema, JSON access, UNNEST, castinggo-minitrace help duckdb-query-recipes — ready-to-use SQL examples that can be ported to mt.query() in JSgo-minitrace help query-duckdb — preset list, --sql-file, archive loading flags for running ad hoc queries alongside JS commandsgo-minitrace help getting-started — step-by-step tutorial from install through first querytestdata/query-repositories/js-showcase/ — worked examples demonstrating every practical JS patterntestdata/query-repositories/mixed-sql-js-showcase/ — side-by-side SQL and JS equivalents for direct comparison