Skip to content

Commit 48ecb4b

Browse files
authored
resolve query tables by SQL name (#119)
1 parent 03d67b8 commit 48ecb4b

11 files changed

Lines changed: 377 additions & 83 deletions

File tree

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ Freshness is treated asymmetrically (since v1.7.0):
299299

300300
Use `ctvs query refresh <file.jsonl>` to refresh selected source files, or
301301
`ctvs query refresh --all [dataset]` when you explicitly want the broader
302-
walk. Use `--refresh always` to force a refresh before the query runs. Use
302+
walk. Repeat `--date` to query or refresh several UTC date partitions at once.
303+
Use `--refresh always` to force a refresh before the query runs. Use
303304
`--strict-freshness` to restore the pre-1.7 behavior where stale partitions
304305
are a hard error (useful in CI / scheduled jobs that must never read
305306
outdated data).
@@ -310,7 +311,12 @@ outdated data).
310311
> unchanged; the new warning is written only to stderr. `missing`
311312
> partitions still error.
312313
313-
Logical datasets are `logs`, `traces`, `metrics`, `proxy_messages`, and `gascity_messages`. `ctvs collect <file.jsonl> --name <name>` registers an external JSONL file as a dynamic table; `ctvs collect --glob '<pattern>' --name <name>` backs one table with many source files. Names are normalized for SQL, so `--name random-log` becomes table `random_log`. Collection tables include `_ctvs_source_path`, `_ctvs_line_number`, `_ctvs_raw`, and inferred top-level JSON fields. Deleted glob sources remain queryable from their cache-only partitions until the collection is removed. `ctvs query schema <dataset>` prints the schema, and `ctvs query catalog` shows which datasets have source and cached rows.
314+
Logical datasets are `logs`, `traces`, `metrics`, `proxy_messages`, and `gascity_messages`. `ctvs collect <file.jsonl> --name <name>` registers an external JSONL file as a dynamic table; `ctvs collect --glob '<pattern>' --name <name>` backs one table with many source files. Names are normalized for SQL, so `--name random-log` becomes table `random_log`; quoted SQL can also reference the original collection name as `"random-log"`. Collection tables include `_ctvs_source_path`, `_ctvs_line_number`, `_ctvs_raw`, and inferred top-level JSON fields. Deleted glob sources remain queryable from their cache-only partitions until the collection is removed. `ctvs query schema <table>` prints the schema, and `ctvs query catalog` shows which datasets have source and cached rows.
315+
316+
```bash
317+
ctvs query sql "select date, count(*) from proxy_messages group by date" \
318+
--date 2026-05-14 --date 2026-05-15 --refresh always
319+
```
314320

315321
### Conversation log model
316322

skills/collectivus-query/SKILL.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: collectivus-query
3-
description: Inspect local Collectivus recordings with the ctvs query CLI. Use when the user asks about recorded logs, traces, metrics, LLM proxy exchanges, query cache freshness, or wants SQL over local Collectivus data.
3+
description: Inspect local Collectivus recordings with the ctvs query CLI. Use when the user asks about recorded logs, traces, metrics, LLM proxy exchanges, query cache freshness, or wants SQL over local Collectivus data, including collected JSONL tables.
44
---
55

66
# Collectivus Query
@@ -18,6 +18,7 @@ Use `ctvs query` to inspect local Collectivus recordings. It reads local JSONL r
1818
- Pass `--strict-freshness` only when the user explicitly needs the pre-1.7 strict mode (e.g., scheduled checks that must never read stale data); it turns stale partitions back into a hard error.
1919
4. Prefer structured output for analysis: use `--format json` for follow-up reasoning, `--format markdown` when showing a table to the user, and `--limit` to keep output bounded.
2020
5. Use high-level query commands before custom SQL. Switch to `ctvs query sql` only when the built-in commands cannot answer the question.
21+
6. For unfamiliar SQL tables, run `ctvs query schema <table> --format json` before querying. It works for built-in recording tables and tables registered with `ctvs collect`.
2122

2223
## Common Commands
2324

@@ -30,6 +31,7 @@ ctvs query logs --since 1h --format json
3031
ctvs query traces slow --limit 20 --format json
3132
ctvs query metrics list --format json
3233
ctvs query metrics series <metric-name> --format json
34+
ctvs query schema <table> --format json
3335
ctvs query proxy get <conversation-id> --format json
3436
ctvs query proxy stats --format json
3537
ctvs query errors --since 24h --format json
@@ -39,7 +41,9 @@ ctvs collect <file.jsonl> --name <name>
3941
ctvs collect --glob '<pattern>' --name <name>
4042
```
4143

42-
`ctvs collect` registers an external local JSONL file as a dynamic SQL table and immediately refreshes its query cache. Collection names are normalized for SQL (`random-log` -> `random_log`). Query them with `ctvs query sql "select * from random_log"`. Pass `--glob '<pattern>'` instead of a single path to back one logical table with many files; each matched file becomes its own cache partition and `_ctvs_source_path` tells you which file a row came from.
44+
`ctvs collect` registers an external local JSONL file as a dynamic SQL table and immediately refreshes its query cache. `ctvs query sql` resolves table names from the SQL AST and injects built-in recording tables plus registered collection tables by name. Collection SQL can use either the normalized table name (`random-log` -> `random_log`) or the original quoted collection name (`"random-log"`), for example `ctvs query sql 'select * from "random-log"'`. Pass `--glob '<pattern>'` instead of a single path to back one logical table with many files; each matched file becomes its own cache partition and `_ctvs_source_path` tells you which file a row came from.
45+
46+
Repeat `--date` to query or refresh multiple UTC date partitions at once, for example `ctvs query sql "select count(*) from proxy_messages" --date 2026-05-14 --date 2026-05-15`.
4347

4448
## Proxy conversation log model
4549

@@ -109,9 +113,9 @@ Use `JSON_VALUE(<col>, '$.path')` to extract scalars from the `attributes` / `st
109113
- Do not assume the cache auto-refreshes. Query commands default to `--refresh never`, and stale partitions return data with a stderr warning rather than refreshing themselves.
110114
- Always read stderr. A successful exit code does not mean the cache is current — a `warning: query cache last refreshed at …` line on stderr means stdout reflects cache rows from that refresh, and the user should be told before drawing conclusions.
111115
- Do not paste `--config` into every command by habit. Use it when discovery shows the service is not using `~/.hyp/collectivus.json`.
112-
- Do not read arbitrary Parquet files directly for `ctvs query sql`; the CLI only allows logical tables.
113-
- Keep SQL read-only and use only logical datasets: `logs`, `traces`, `metrics`, `proxy_messages`, `gascity_messages`, and registered collection tables from `ctvs query catalog`.
114-
- Use UTC dates with `--date YYYY-MM-DD`.
116+
- Do not read arbitrary Parquet or Iceberg files directly for `ctvs query sql`; the CLI resolves SQL table names and injects only known query tables.
117+
- Keep SQL read-only and use only query tables from `ctvs query catalog`: built-ins (`logs`, `traces`, `metrics`, `proxy_messages`, `gascity_messages`) and registered collection tables.
118+
- Use UTC dates with `--date YYYY-MM-DD`; repeat `--date` when the user wants a union across multiple date partitions.
115119
- Use `--service`, `--gateway-id`, `--from`, `--to`, or `--since` to narrow broad investigations.
116120

117121
## Reference
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
interface:
22
display_name: "Collectivus Query"
33
short_description: "Query local Collectivus recordings"
4-
default_prompt: "Use $collectivus-query to inspect local Collectivus logs, traces, metrics, or LLM proxy messages."
4+
default_prompt: "Use $collectivus-query to inspect local Collectivus logs, traces, metrics, LLM proxy messages, gascity messages, or collected JSONL tables."
55
policy:
66
allow_implicit_invocation: true

skills/collectivus-query/references/query-cli.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ External JSONL collections registered with `ctvs collect <file.jsonl> --name <na
1212
<recording-root>/.collectivus-query/collections.json
1313
```
1414

15-
Their query cache lives under `<recording-root>/.collectivus-query/cache/collections/<table>/source=<hash>/cursor.json`, with rows stored in local Iceberg tables below each source partition. Names are normalized for SQL, so `--name random-log` exposes table `random_log`.
15+
Their query cache lives under `<recording-root>/.collectivus-query/cache/collections/<table>/source=<hash>/cursor.json`, with rows stored in local Iceberg tables below each source partition. SQL can reference either the normalized table name (`--name random-log` exposes `random_log`) or the original quoted collection name (`"random-log"`).
1616

1717
The cache is explicit. Query commands do not refresh it unless `--refresh always` is passed.
1818

@@ -32,7 +32,7 @@ Commands default to `~/.hyp/collectivus.json`. If the running gateway or OTEL co
3232
- `--cache-dir <dir>`: Override the query cache directory.
3333
- `--from <timestamp>` / `--to <timestamp>`: Inclusive timestamp bounds.
3434
- `--since <duration>`: Relative lower bound such as `15m`, `2h`, or `7d`.
35-
- `--date <YYYY-MM-DD>`: Restrict to one UTC date partition.
35+
- `--date <YYYY-MM-DD>`: Restrict to one UTC date partition. Repeat it to query or refresh multiple days.
3636
- `--gateway-id <id>`: Restrict to one gateway id.
3737
- `--service <name>`: Restrict `serviceName` for logs, traces, and metrics.
3838
- `--limit <n>`: Maximum rows to render. Default `100`, maximum `1000`.
@@ -47,7 +47,7 @@ Commands default to `~/.hyp/collectivus.json`. If the running gateway or OTEL co
4747
- `ctvs query doctor`: Check config, recording root, source files, and cache freshness.
4848
- `ctvs query status`: Inspect source partitions and cache freshness.
4949
- `ctvs query catalog`: List logical datasets, columns, source partitions, and cached row counts.
50-
- `ctvs query schema <dataset>`: Print static schema for a logical dataset.
50+
- `ctvs query schema <table>`: Print schema for a built-in or collected query table.
5151
- `ctvs query refresh <file.jsonl>... [--force]`: Materialize selected JSONL source files into the query cache.
5252
- `ctvs query refresh --all [dataset] [--force]`: Materialize all matching JSONL source files into the query cache.
5353
- `ctvs query sample <dataset>`: Show sample rows.
@@ -69,9 +69,10 @@ Use `ctvs collect` to register arbitrary local JSONL files as dynamic query tabl
6969
ctvs collect random-log.jsonl --name random-log
7070
ctvs collect --glob '/path/to/segments/**/*.jsonl' --name segments
7171
ctvs query sql "select * from random_log" --format json
72+
ctvs query sql 'select * from "random-log"' --format json
7273
```
7374

74-
`ctvs collect` stores the absolute source path (or glob) and immediately refreshes the query cache. If the source file changes later, normal query freshness rules apply: stale cached data is queryable with a stderr warning, `--strict-freshness` turns that into an error, and `ctvs query refresh <file.jsonl>` refreshes selected files. Use `--refresh always` to refresh before running the query.
75+
`ctvs collect` stores the absolute source path (or glob) and immediately refreshes the query cache. If the source file changes later, normal query freshness rules apply: stale cached data is queryable with a stderr warning, `--strict-freshness` turns that into an error, and `ctvs query refresh <file.jsonl>` refreshes selected files. Use `--refresh always` to refresh before running the query. SQL can reference the normalized table name or the original quoted collection name, such as `"random-log"`.
7576

7677
With `--glob`, one logical table is backed by many source files: each matched file becomes its own cache partition under `.collectivus-query/cache/collections/<table>/source=<hash>/cursor.json`, and refresh appends from each file's recorded cursor when possible. Files that no longer match the glob remain queryable as cache-only partitions. Inside SQL, use `_ctvs_source_path` to see which file a row came from.
7778

@@ -85,7 +86,7 @@ Collection tables always include `_ctvs_source_path`, `_ctvs_line_number`, and `
8586
- `proxy_messages`: One row per LLM proxy content part (text block, tool call, tool result, etc.), globally deduped by content-derived `message_id`. See **proxy_messages columns** below for the full 26-column schema; `gateway_id` and `date` are added as partition columns in the query cache.
8687
- `gascity_messages`: One row per content block from gascity-captured agent sessions (text, thinking, tool_use, tool_result, attachment). Captured by the `ctvs gascity` supervisor source — agent-attributed (`gascity_template` / `gascity_rig` / `gascity_alias`) and includes per-frame token usage with cache breakdown. Always fresh: the daemon writes Parquet directly to `~/.collectivus/sink/gascity_messages/date=<YYYY-MM-DD>/city=<name>/` (no JSONL stage, no `.meta.json` sidecar). The constant `gateway_id = 'gascity-scribe'` tags the source for cross-source UNIONs with `proxy_messages`. Run `ctvs query schema gascity_messages --format markdown` for the full 47-column schema.
8788

88-
Run `ctvs query schema <dataset> --format json` for the exact columns in the installed version.
89+
Run `ctvs query schema <table> --format json` for the exact columns in the installed version. Schema lookup works for built-in tables and tables registered with `ctvs collect`.
8990

9091
## proxy_messages columns
9192

@@ -129,6 +130,7 @@ ctvs query sql "select serviceName, count(*) as logs from logs group by serviceN
129130
ctvs query sql "select traceId, name, durationMs from traces order by durationMs desc limit 20" --refresh always --format json
130131
ctvs query sql "select model, count(distinct message_id) as messages, count(*) as parts from proxy_messages where role = 'assistant' group by model order by messages desc" --format markdown
131132
ctvs query sql "select conversation_id, count(distinct message_id) as messages from proxy_messages group by conversation_id order by messages desc limit 10" --format markdown
133+
ctvs query sql "select date, count(*) as parts from proxy_messages group by date order by date" --date 2026-05-14 --date 2026-05-15 --format markdown
132134
```
133135

134136
For JSON columns (`attributes`, `status`, `tools`, `tool_args`), extract scalars with `JSON_VALUE(<col>, '$.path')`:
@@ -137,4 +139,4 @@ For JSON columns (`attributes`, `status`, `tools`, `tool_args`), extract scalars
137139
ctvs query sql "select model, sum(cast(JSON_VALUE(attributes, '\$.usage.input_tokens') as bigint)) as input_tokens from (select distinct message_id, model, attributes from proxy_messages where role = 'assistant') group by model order by input_tokens desc" --format markdown
138140
```
139141

140-
SQL must be a read-only `select` over the logical datasets above or registered collection tables.
142+
SQL must be a read-only `select` over known query tables. Table names are resolved from the SQL AST and may be built-ins (`logs`, `traces`, `metrics`, `proxy_messages`, `gascity_messages`) or registered collection tables from `ctvs query catalog`.

0 commit comments

Comments
 (0)