@carllee1983/dbcli 1.51.2 → 1.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  ---
2
- name: dbcli
3
- description: Database CLI for AI agents with permission-based access control. Use to set up new connections, query, inspect schemas, insert/update/delete, export results, generate DB reports or interactive HTML dashboards, and blacklist sensitive columns/tables. Supports MySQL, PostgreSQL, MariaDB, MongoDB, Redis, and Elasticsearch with multiple named connections per project and custom env files. Trigger when configuring a database connection (`.dbcli` / `.env`), choosing between v1 single and v2 multi-connection layouts, picking auth modes (URI, env refs, Cloud ID, API key), running SQL / MongoDB JSON / Redis commands / Elasticsearch DSL, generating a report/dashboard/HTML UI from raw SQL or saved snippets, exploring table/collection/key/index structures, switching database environments, protecting sensitive data from AI access, or performing automated recovery and guided remediation after command failures. For exhaustive flags and examples, read the sibling `reference.md`.
2
+ description: Database CLI for AI agents with permission-gated access to MySQL, PostgreSQL, MariaDB, MongoDB, Redis, and Elasticsearch. Trigger when: wiring up a connection (`.dbcli` / `.env`, v1 single vs v2 multi-connection, auth mode); running SQL / MongoDB JSON / Redis commands / Elasticsearch DSL; inspecting table, collection, key, or index structure; writing rows or exporting results; building a report, dashboard, or HTML UI; authoring or reviewing a schema design; protecting sensitive data with the blacklist; or recovering after a failed command. For exhaustive flags and examples, read the companion `../skills/dbcli/reference.md`.
3
+ globs:
4
+ alwaysApply: false
4
5
  ---
5
-
6
6
  # dbcli
7
7
 
8
8
  Database CLI for AI agents with permission-based access control.
@@ -71,7 +71,7 @@ afterwards add only the `@diag/*` it does not cover (`missing-indexes`, `locks`,
71
71
  `export` / `schema` / `inspect` / `lint` / `diff --against-orm`. The command emits a `RecoveryEnvelope` to stdout and saves
72
72
  it to `.dbcli/last-recovery.json`; then `dbcli recover` inspects it and `dbcli recover --apply`
73
73
  runs the saved plan under risk gating. Multi-turn `--next`, connection branching, and the
74
- post-apply verify probe are documented in reference.md §Recovery Cookbook.
74
+ post-apply verify probe are documented in [reference.md](../skills/dbcli/reference.md#recovery-cookbook-agent-walkthroughs).
75
75
 
76
76
  When reporting a check's outcome use the vocabulary `verified` (evidence matched) /
77
77
  `not_verified` (check ran and contradicted) / `indeterminate` (ran but ambiguous) /
@@ -157,6 +157,8 @@ in **How to use dbcli** still applies.
157
157
  | DB report / dashboard request | `blacklist list` → `queries search <keywords>` / `queries suggest <intent>` → `queries show @<name>` → `q @<name> --ui` or `--format html` |
158
158
  | Application data bug | `audit tail --for-agent --n 10` → `blacklist list` → `schema <object>` → narrow query |
159
159
  | ORM or migration work | `schema --format json` → `diff --against-orm <orm-schema>` → review error-level drift → proposals via `migrate` (dry-run) → `migration-review` task pack → `diff --against <snapshot>` after applying. |
160
+ | Schema design, no database yet | `design init --output ./dbcli.design.json` → edit → `design validate` → `design render --format mermaid`. With existing ORM models, reconcile via `design diff --against-orm <path>` first. |
161
+ | Design drift on a live database | `blacklist list` → `schema --format json` → `design diff --against-cache` → `design propose --against-cache`, then hand the plan to a human before any migration. |
160
162
  | PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
161
163
  | Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
162
164
  | Safe data backfill | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back or snippet `--verify`. |
@@ -193,12 +195,14 @@ Guardrails:
193
195
  - Separate database facts from application-code inference. Report which dbcli output shaped the conclusion.
194
196
  - For writes and backfills, include scope count, dry-run preview, execution command, and read-back.
195
197
  - Do not create indexes directly from a performance suggestion; turn them into reviewed migrations.
198
+ - Do not execute the `commands` in a `design propose` plan, and do not create or rewrite
199
+ `dbcli.design.json` unless a human asked for it.
196
200
  - Do not print credentials, copied connection strings, or blacklisted values.
197
201
  - Durable evidence: `assert … --write-verification-artifact --verification-subject <kind:name>`;
198
202
  inspect with `verification summary` / `list` / `show <id>`. The `verify safe-backfill` /
199
203
  `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>`
200
204
  family runs preflight + `--after-write` checks and **never executes the write**. Full flags
201
- and the per-command blocks are in reference.md.
205
+ and the per-command blocks are in [reference.md](../skills/dbcli/reference.md#commands).
202
206
 
203
207
  ## Audit log
204
208
 
@@ -215,7 +219,7 @@ The `inspect` / `guide` / `recover` agent JSON embeds `audit_recent` (last 5 ent
215
219
  fresh session has immediate history. An envelope's `audit_ref` and an audit entry's
216
220
  `recovery_ref` point at each other, so you can pivot either way. Audit is on by default
217
221
  (`audit.enabled = false` to opt out); entries are metadata-only (never SQL bodies, `--param`
218
- values, or result cells) and rotate at ~10 MB / 1000 entries. Full flags: reference.md §audit.
222
+ values, or result cells) and rotate at ~10 MB / 1000 entries. Full flags: [reference.md](../skills/dbcli/reference.md#audit).
219
223
 
220
224
  ## Quick start
221
225
 
@@ -318,7 +322,7 @@ dbcli --global query "SELECT 1"
318
322
  Each named connection has its own schema cache at `.dbcli/schemas/<connection>/`. Run
319
323
  `dbcli schema --use <name>` once per connection **before** `schema <table>` — otherwise the
320
324
  cache may serve another connection's columns. `schema --refresh` / `--reset` manage the cache
321
- (reference.md). `--skip-test` skips the init-time TCP connection test; it is implied
325
+ (../skills/dbcli/reference.md). `--skip-test` skips the init-time TCP connection test; it is implied
322
326
  automatically when `--use-env-refs` is set (the `$env` refs have no value to connect with yet).
323
327
  `--system` is optional for v2 — without it the engine is inferred from `--env-file` / `.env`
324
328
  (`DATABASE_URL` scheme), defaulting to `postgresql`.
@@ -371,7 +375,7 @@ refs have no value to connect with yet.
371
375
  - **Re-running `init`** — refuses to overwrite without `--force`; never use
372
376
  `--force` to "fix" a config full of `{ "$env": "..." }` refs.
373
377
 
374
- Full flags and edge cases: see [reference.md](reference.md) `init` section.
378
+ Full flags and edge cases: see [reference.md](../skills/dbcli/reference.md#init).
375
379
 
376
380
  ## Command overview
377
381
 
@@ -381,33 +385,34 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
381
385
  | `use` | n/a | Show/switch default named connection (v2 only). |
382
386
  | `list` | query-only+ | Tables (SQL), collections (MongoDB), keys (Redis), or indices (Elasticsearch). |
383
387
  | `schema` | query-only+ | SQL: per-table or full scan into `.dbcli/schemas/`. MongoDB: sampled. ES: flattened mapping. Redis: per-key only (type/TTL/size). Supports `--recovery`. |
384
- | `query` | query-only+ | SQL, Mongo JSON (`--collection`), Redis command, or ES DSL/Lucene (`--collection`). `--format table\|json\|csv\|html`, `--ui` to open the interactive dashboard in a browser. `--fields` (projection), `--truncate` (cell width), `-f/--query-file` (read query from file or stdin), `--use a,b` (read-only fan-out). Supports `--recovery`. See **Query workflow flags**. |
385
- | `explain` | query-only+ | **(v1.23)** Read-only query plan with annotations. SQL only. Single query, `@saved-query`, `@file.sql`, or `--bulk @glob/*`. `--analyze` (EXPLAIN ANALYZE / MariaDB ANALYZE SELECT), `--format markdown\|json\|table`. |
388
+ | `query` | query-only+ | SQL, Mongo JSON (`--collection`), Redis command, or ES DSL/Lucene (`--collection`). `--format table\|json\|csv\|html`, `--ui` to open the interactive dashboard in a browser. `--fields` (projection), `--truncate` (cell width), `-f/--query-file` (read query from file or stdin), `--use a,b` (read-only fan-out). Supports `--recovery`. `--slow-ms <n>` sets the passive slow-query hint threshold (default 1000, `0` off): at or above it, table output gains a `Performance hint` footer and JSON gains `metadata.performanceAdvisory`; it runs no extra diagnostics and is suppressed under `--recovery`. Distinct from the `proxy` flag of the same name. See **Query workflow flags**. |
389
+ | `explain` | query-only+ | Read-only query plan with annotations. SQL only. Single query, `@saved-query`, `@file.sql`, or `--bulk @glob/*`. `--analyze` (EXPLAIN ANALYZE / MariaDB ANALYZE SELECT), `--format markdown\|json\|table`. |
386
390
  | `lint` | n/a | Static SQL anti-pattern advisor (no DB connection). 9 rules incl. schema-aware implicit-cast / NOT IN-nullable checks via the layered `.dbcli/schemas/` cache; global `--use <conn>` selects a named cache. Findings carry rewrite drafts + guarded `explain` verify commands (`--analyze` only for proven read-only SQL) — report-only, never executes. `--format text\|json\|markdown`, `--min-severity`, `--no-schema`, `--bulk`. Supports `--recovery`. |
387
391
  | `plan` | n/a | Static SQL risk analyzer (`--format text\|json`); classifies a statement without connecting to the database. |
388
- | `q` | query-only+ | Run a saved snippet by `@name` with `--param k=v`. Supports `--verify` to run assertions. |
392
+ | `q` | query-only+ | Run a saved snippet by `@name` with `--param k=v`. Supports `--verify` to run assertions and `--slow-ms <n>` (same passive slow-query hint as `query`). |
389
393
  | `queries` | n/a | Manage saved snippets: `list` / `show` / `search` / `suggest` / `new` / `edit` / `check` / `delete` / `rename` / `copy` / `import` / `export`. |
390
394
  | `insert` / `update` | read-write+ | SQL or MongoDB only. JSON `--data` / `--set`; `--where` required on `update`; `--dry-run` first. Redis writes go through `query`. Supports `--recovery`. |
391
395
  | `delete` | data-admin+ | SQL or MongoDB; Redis has a basic implementation (see Redis section). `--where` required; `--dry-run` first. Supports `--recovery`. |
392
- | `export` | query-only+ | SQL, MongoDB, or **(v1.22)** Elasticsearch (DSL `--index` or whole-index scroll). Query → `--format json\|jsonl\|csv\|html` file or stdout. `html` emits a standalone interactive dashboard. **Fails closed rather than truncating silently**: if the auto-limit would drop rows, the export errors out and you must pass `--no-limit` or `--limit N`. Supports `--recovery`. |
396
+ | `export` | query-only+ | SQL, MongoDB, or Elasticsearch (DSL `--index` or whole-index scroll). Query → `--format json\|jsonl\|csv\|html` file or stdout. `html` emits a standalone interactive dashboard. **Fails closed rather than truncating silently**: if the auto-limit would drop rows, the export errors out and you must pass `--no-limit` or `--limit N`. Supports `--recovery`. |
393
397
  | `blacklist` | n/a | `list` / `table` / `column` subcommands redact sensitive data from query results. |
394
398
  | `check` | query-only+ | SQL only (best on MySQL/MariaDB). |
395
- | `diff` | query-only+ | SQL only. Save/compare schema snapshots. **(P1b)** `--against-orm <path>` compares a Prisma schema / DDL file / normalized JSON against the local schema cache (no DB connection): categorized drift (`missing_in_db` = error, `missing_in_orm` = warn, `mismatch` per tolerance table, `unmanaged`) with dry-run `migrate` proposals; exit 1 on error-level drift. `--orm-format prisma\|ddl\|json\|drizzle\|typeorm\|sequelize`, `--ignore <globs>`, `--format json\|table\|markdown`. Drizzle: point at `drizzle/meta/<NNNN>_snapshot.json` (run `drizzle-kit generate` first; `.ts` sources are rejected with a hint). TypeORM/Sequelize: feed tool-generated DDL (`schema:log` / a schema-only dump); source files are rejected with the exact generation command to run. |
396
- | `snapshot` | query-only+ | **(v1.25)** SQL only. Capture a result fingerprint (`rowCount` + per-column null/distinct/min/max/sum + order-independent checksum). `--out` (default `.dbcli/snapshots/snap-<ts>.json`), `--rows`, `--stdout`, `--format`, `--no-limit`. Baseline for `assert --against`. |
397
- | `assert` | query-only+ | **(v1.25)** SQL only. Verify an invariant; exit 1 on failure unless `--no-fail`. `--expect "rows>0\|value==X\|col:c not null\|unique\|between a and b\|>= n"`, `--vs <query> --compare rows\|value` (reconcile), `--against <snapshot> --tolerance <pct>`. |
399
+ | `diff` | query-only+ | SQL only. Save/compare schema snapshots. `--against-orm <path>` compares a Prisma schema / DDL file / normalized JSON against the local schema cache (no DB connection): categorized drift (`missing_in_db` = error, `missing_in_orm` = warn, `mismatch` per tolerance table, `unmanaged`) with dry-run `migrate` proposals; exit 1 on error-level drift. `--orm-format prisma\|ddl\|json\|drizzle\|typeorm\|sequelize`, `--ignore <globs>`, `--format json\|table\|markdown`. Drizzle: point at `drizzle/meta/<NNNN>_snapshot.json` (run `drizzle-kit generate` first; `.ts` sources are rejected with a hint). TypeORM/Sequelize: feed tool-generated DDL (`schema:log` / a schema-only dump); source files are rejected with the exact generation command to run. |
400
+ | `design` | n/a | Offline SQL design assistant over a version-controlled `dbcli.design.json`: never connects, never runs DDL, never calls a provider. `init --output <path>` is the only writer and refuses to overwrite; `validate` is fail-closed, so `render` / `diff` / `propose` refuse to run while `error` findings remain. `diff` / `propose` need exactly one of `--against-cache` or `--against-orm <paths>`. **`propose` is review-only — it plans, it never writes.** Naming rules, finding codes, and the artifact shape are in [reference.md](../skills/dbcli/reference.md#design). |
401
+ | `snapshot` | query-only+ | SQL only. Capture a result fingerprint (`rowCount` + per-column null/distinct/min/max/sum + order-independent checksum). `--out` (default `.dbcli/snapshots/snap-<ts>.json`), `--rows`, `--stdout`, `--format`, `--no-limit`. Baseline for `assert --against`. |
402
+ | `assert` | query-only+ | SQL only. Verify an invariant; exit 1 on failure unless `--no-fail`. `--expect "rows>0\|value==X\|col:c not null\|unique\|between a and b\|>= n"`, `--vs <query> --compare rows\|value` (reconcile), `--against <snapshot> --tolerance <pct>`. |
398
403
  | `verification` | n/a | Inspect and manage local verification artifacts. `list` / `show <id-or-path>` / `summary` are read-only; `prune` is dry-run by default and deletes only with `--execute --force`. Reads `<cwd>/.dbcli/verification/`; no DB connection, no audit writes. |
399
404
  | `backfill artifact` | n/a | Build a bounded, reviewable source-to-SQL backfill artifact from JSON. Includes source/target identity, blacklist/schema preflight, read-back verification, and rollback hints; dry-run only and never executes writes. |
400
- | `proxy` | n/a | **(v1.26)** MySQL/MariaDB/PostgreSQL only. Local-dev observability proxy — relays app traffic to the real DB and appends query/latency/byte/error events to `.dbcli/proxy/events.jsonl`. Subcommands: `mysql` \| `mariadb` \| `postgresql`. `--listen`, `--target`, `--events` (default `.dbcli/proxy/events.jsonl`), `--slow-ms` (default `1000`), `--redact none\|literals` (default `none`). Observe-only. **(v1.27)** `proxy analyze` aggregates the event log offline into a JSON/text report (summary, byFingerprint, slowest, errors, hotTables, N+1) `--format`, `--top`, `--slow-ms`, `--n-plus-one`; errors out if no events exist yet. **(v1.50)** `proxy analyze --format markdown` produces the QueryLens report and redacts SQL/error literals in-memory before analysis; use `proxy <engine> --redact literals` to protect the log itself. Actionable blocks carry `suggestedCommands` + `hints` so an agent can act: SELECT hotspots/N+1 `explain` / `guide missing-index-for`, errors → `schema <table>` (verify names, never guess), N+1 batch (JOIN / `IN (...)`). After analyzing, run each finding's `suggestedCommands`, read its `hints`, then propose the fix. |
405
+ | `proxy` | n/a | MySQL/MariaDB/PostgreSQL only. Local-dev observability proxy — relays app traffic to the real DB and appends query/latency/byte/error events to `.dbcli/proxy/events.jsonl`. Observe-only. `proxy analyze` aggregates that log offline (summary, byFingerprint, slowest, errors, hotTables, N+1; `--format markdown` produces the QueryLens report) and errors out if no events exist. Act on it: run each finding's `suggestedCommands`, read its `hints`, then propose the fix never guess a table name, confirm with `schema`. Protect the log itself with `--redact literals`. [Flags](../skills/dbcli/reference.md#proxy). |
401
406
  | `status` | query-only+ | Safe JSON/text summary (no credentials). |
402
- | `inspect` | query-only+ | Read-only context snapshot (connection, permission, blacklist, objects, snippets, context-aware `suggestedCommands`, and **(v1.23)** human-readable `hints`). `--for-agent` / `--brief` / `--no-connect` / `--require-schema-cache`. Supports `--recovery`. |
407
+ | `inspect` | query-only+ | Read-only context snapshot (connection, permission, blacklist, objects, snippets, context-aware `suggestedCommands`, and human-readable `hints`). `--for-agent` / `--brief` / `--no-connect` / `--require-schema-cache`. Supports `--recovery`. |
403
408
  | `report` | query-only+ | Diagnostic report built from `@diag/*` snippets. `--section <health\|capacity\|perf>` (comma-separated to combine), `--brief`, `--for-agent`, `--no-connect`. |
404
- | `guide` | query-only+ | Deterministic next-command plan for a fixed goal (`slow-query`, `capacity`, `health`, `index-usage`, `permissions`, `schema-overview`). `--list` to enumerate. **(v1.23)** `guide missing-index-for <query>` suggests composite indexes for a single SELECT (`--format yaml\|json\|markdown`, `--min-confidence`). |
409
+ | `guide` | query-only+ | Deterministic next-command plan for a fixed goal (`slow-query`, `capacity`, `health`, `index-usage`, `permissions`, `schema-overview`). `--list` to enumerate. `guide missing-index-for <query>` suggests composite indexes for a single SELECT (`--format yaml\|json\|markdown`, `--min-confidence`). |
405
410
  | `recovery` | n/a | Look up the structured `RecoveryEnvelope` for a known error code (`--code <CODE>` or `--list`). Standalone synthesizer; does not require a real failure. |
406
411
  | `recover` | n/a | Inspect (default) or `--apply` the auto-saved recovery plan in `.dbcli/last-recovery.json`. `--allow-write=readonly-cmd\|write-cmd`, `--no-verify`, `--from <file>`, `--next --after-step <n> --result <json\|@file>` for multi-turn step-at-a-time. |
407
412
  | `doctor` | n/a | Environment/runtime identity, config, connection, SRV diagnostics (Mongo), schema cache age. `--format json --remediation` emits candidate-only blacklist/schema/bounded-sample plans (SQL: `dbcli plan` → human-confirmed bounded `dbcli query`; MongoDB/Elasticsearch: `dbcli schema` preflight → human-confirmed bounded query); it never applies them. |
408
413
  | `completion` | n/a | bash / zsh / fish scripts. |
409
414
  | `upgrade` | n/a | Self-update from npm; 24h-cached version hints on every command. |
410
- | `shell` | (same as query+) | Interactive REPL. SQL engines, MongoDB, and Redis (single-line; `.no-limit on/off`). **(v1.22)** Elasticsearch opens a Kibana Dev Tools-style REPL (`<METHOD> /<path>` + optional JSON body, blank line submits). |
415
+ | `shell` | (same as query+) | Interactive REPL. SQL engines, MongoDB, and Redis (single-line; `.no-limit on/off`). Elasticsearch opens a Kibana Dev Tools-style REPL (`<METHOD> /<path>` + optional JSON body, blank line submits). |
411
416
  | `skill` | n/a | Generate / install AI skill docs (`--install <claude\|gemini\|antigravity\|copilot\|cursor\|codex\|windsurf>`); `skill tasks list/show/plan` for Agent Task Packs; `skill context` for an LLM prompt-context payload (for injecting into another LLM, not needed for normal operation). |
412
417
  | `semantic` | n/a | Validate, search, inspect drift, migrate to v2, or print the optional project-root `dbcli.semantic.json`. Give its reviewed context to an external agent, but keep provider credentials, prompts, and agent context outside dbcli. `semantic draft validate --input <file|-> [--format text\|json]` validates only the explicit untrusted `QueryDraft` offline against local semantic/schema/saved-query metadata; it returns safe hashes/references/violation codes, never executes or echoes candidate SQL. Review the original draft, then invoke `explain` or `query` separately if intended. |
413
418
  | `migrate` | admin | SQL only. **DDL; dry-run by default** — needs `--execute`. |
@@ -475,12 +480,12 @@ truncation from a round number. This applies to `query` and to `q` snippets
475
480
  explicit operators (`$set`/`$inc`/`$push`/…) pass through. Nested blacklist accepts dotted
476
481
  paths (`profile.email`) and trailing wildcards (`profile.tokens.*`). Saved snippets end in
477
482
  `.mongodb.sql` (frontmatter `engine: mongodb`, `operation: find|aggregate`). Full
478
- write-planner tiers and syntax: reference.md MongoDB section.
483
+ write-planner tiers and syntax: [reference.md](../skills/dbcli/reference.md#mongodb-support).
479
484
 
480
485
  ## Redis
481
486
 
482
487
  - `query` runs a single **whitelisted** Redis command (e.g. `GET`, `SET`, `HSET`, `DEL`).
483
- The full whitelist and the per-command permission tier are defined in reference.md.
488
+ The full whitelist and the per-command permission tier are defined in [reference.md](../skills/dbcli/reference.md#redis-support).
484
489
  - **Supported:** `init`, `list` (keys via SCAN), `schema <key>` (type / TTL / size / sample),
485
490
  `query`, `q` (saved snippets — **read-only commands only**), `delete` (basic implementation:
486
491
  `DEL` / `HDEL` / `LREM` / `SREM` / `ZREM`, needs `data-admin`; `query "DEL <key>"` also
@@ -493,7 +498,7 @@ truncation from a round number. This applies to `query` and to `q` snippets
493
498
  blacklist (matching reads/writes are rejected). To preview a delete, use `delete <key> --dry-run`.
494
499
  - `database` is the logical DB index (default `0`). `dbcli blacklist table add 'secrets:*'`
495
500
  registers a key glob; an optional `redis.mask` block masks values on read. Size guards
496
- (SCAN/HGETALL truncation, `--no-limit` to bypass) and masking details: reference.md Redis section.
501
+ (SCAN/HGETALL truncation, `--no-limit` to bypass) and masking details: [reference.md](../skills/dbcli/reference.md#redis-support).
497
502
 
498
503
  ## Elasticsearch
499
504
 
@@ -505,12 +510,14 @@ dbcli query '{"query":{"match":{"status":"active"}}}' --collection orders
505
510
 
506
511
  - `query` takes a DSL (JSON body) or Lucene query string; `--collection <index>` is required.
507
512
  - **Supported:** `init`, `list` (indices with doc count), `schema [index]` (flattened mapping),
508
- `query`, `export` (v1.22), `shell` (v1.22), `status`, `use`, `doctor`. **Not supported:**
513
+ `query`, `q` (snippets use the `.elasticsearch.sql` extension), `export`,
514
+ `shell`, `status`, `use`, `doctor`. **Not supported:**
509
515
  `insert`, `update`, `delete`, `check`, `diff`, `migrate`.
510
516
  - `export` takes a search DSL with `--index <index>`, or an index name as the query to scroll
511
- the whole index via `match_all`. Query-only caps at 1000 hits; `--no-limit` is bounded at 10 000.
517
+ the whole index via `match_all`. Query-only caps at 1000 hits; `--no-limit` streams the whole
518
+ index via the scroll API. (The 10 000 bound belongs to `query`, not `export`.)
512
519
  - Schema flattens nested fields (`a.b.c`) and surfaces `.fields` multi-fields. `shell` opens a
513
- Kibana Dev Tools-style REPL. Full syntax and examples: reference.md Elasticsearch section.
520
+ Kibana Dev Tools-style REPL. Full syntax and examples: [reference.md](../skills/dbcli/reference.md#elasticsearch-support).
514
521
 
515
522
  ## Saved queries
516
523
 
@@ -575,7 +582,7 @@ dbcli export "SELECT * FROM orders" --format html --output orders.html
575
582
  When a saved snippet exists, prefer `q @<name> --ui` / `q @<name> --format html` because snippet
576
583
  metadata can drive titles, KPI cards, and charts. Blacklist redaction is applied **before**
577
584
  rendering. To get KPIs and charts instead of a plain table, add a `visual:` block (`title`,
578
- `kpis[]`, `charts[]`) to the snippet frontmatter — see reference.md for the full `visual:`
585
+ `kpis[]`, `charts[]`) to the snippet frontmatter — see [reference.md](../skills/dbcli/reference.md#interactive-html-dashboard) for the full `visual:`
579
586
  schema. Raw `query` / `export` invocations render a sortable table only.
580
587
 
581
588
  ## Common workflows
@@ -592,6 +599,6 @@ schema. Raw `query` / `export` invocations render a sortable table only.
592
599
 
593
600
  - Query-only mode auto-appends `LIMIT 1000`; add `--no-limit` for `information_schema` or statements that break with `LIMIT`.
594
601
  - Blacklisted tables and columns are redacted from query output.
595
- - `schema` reports `estimatedRowCount` and `sizeCategory` (small / medium / large / huge). For large/huge tables add `WHERE` or `LIMIT` — bands in reference.md.
602
+ - `schema` reports `estimatedRowCount` and `sizeCategory` (small / medium / large / huge). For large/huge tables add `WHERE` or `LIMIT` — bands in [reference.md](../skills/dbcli/reference.md#schema).
596
603
  - `doctor` on `mongodb+srv://` reports whether SRV resolves natively or through the DoH fallback — useful when the runtime restricts DNS.
597
604
  - **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
@@ -4,6 +4,66 @@ Companion to [SKILL.md](SKILL.md). Exhaustive flags, copy-paste examples, `shell
4
4
 
5
5
  For cross-engine support status, see `docs/feature-matrix.md` in the repository.
6
6
 
7
+ ## Index
8
+
9
+ Jump straight to what you need — this file is long, and reading it end to end is
10
+ never the right move.
11
+
12
+ | Section | What is in it |
13
+ |---|---|
14
+ | [Global options and placement](#global-options-and-placement) | Flags that must precede the command (`--use`, `--config`), and [redirecting output](#redirecting-output). |
15
+ | [Commands](#commands) | Every command, one `###` each — see the command list below. |
16
+ | [Recovery Cookbook](#recovery-cookbook-agent-walkthroughs) | Failure-to-fix walkthroughs S1–S6, the [scenario index](#scenario-index), [risk gate cheat sheet](#risk-gate-cheat-sheet), and [common pitfalls](#common-pitfalls). |
17
+ | [Interactive HTML dashboard](#interactive-html-dashboard) | `--ui` / `--format html`: [entry points](#entry-points), [data injection contract](#data-injection-contract), [`meta` shape](#meta-shape). |
18
+ | [MongoDB Support](#mongodb-support) | Connection shapes, JSON query bodies, write-stage guard. |
19
+ | [Redis Support](#redis-support) | Command permission tiers, size guards, key masking. |
20
+ | [Elasticsearch Support](#elasticsearch-support) | DSL and Lucene queries, scroll export, mapping flattening. |
21
+
22
+ **Commands** —
23
+ [init](#init) ·
24
+ [use](#use) ·
25
+ [list](#list) ·
26
+ [schema](#schema) ·
27
+ [query](#query) ·
28
+ [explain](#explain) ·
29
+ [lint](#lint) ·
30
+ [plan](#plan) ·
31
+ [q](#q) ·
32
+ [queries](#queries) ·
33
+ [insert](#insert) ·
34
+ [update](#update) ·
35
+ [delete](#delete) ·
36
+ [export](#export) ·
37
+ [blacklist](#blacklist) ·
38
+ [check](#check) ·
39
+ [diff](#diff) ·
40
+ [design](#design) ·
41
+ [snapshot](#snapshot) ·
42
+ [assert](#assert) ·
43
+ [proxy](#proxy) ·
44
+ [status](#status) ·
45
+ [inspect](#inspect) ·
46
+ [report](#report) ·
47
+ [guide](#guide) ·
48
+ [recovery](#recovery) ·
49
+ [recover](#recover) ·
50
+ [audit](#audit) ·
51
+ [verify](#verify) ·
52
+ [verification](#verification) ·
53
+ [backfill](#backfill) ·
54
+ [doctor](#doctor) ·
55
+ [completion](#completion) ·
56
+ [upgrade](#upgrade) ·
57
+ [shell](#dbcli-shell) ·
58
+ [migrate](#migrate) ·
59
+ [semantic](#semantic) ·
60
+ [skill](#skill) ·
61
+ [skill context](#skill-context) ·
62
+ [skill tasks](#skill-tasks-agent-task-packs)
63
+
64
+ Also worth knowing before you connect:
65
+ [Agent configuration trust boundary](#agent-configuration-trust-boundary).
66
+
7
67
  ## Global options and placement
8
68
 
9
69
  These options are available on the root `dbcli` command. Root-level options must
@@ -220,9 +280,44 @@ dbcli query "SELECT day, dau FROM dau_daily" --ui # open in brows
220
280
  dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdout
221
281
  ```
222
282
 
223
- **Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--recovery`
283
+ **Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--slow-ms <number>`, `--recovery`
224
284
  **Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
225
285
 
286
+ #### Passive slow-query hint (`--slow-ms`)
287
+
288
+ `query` and `q` read the execution time they already measured for a finished
289
+ query and, at or above the threshold, add a hint. Default `1000`; `--slow-ms 0`
290
+ disables it for that invocation. This is **not** the `proxy` / `proxy analyze`
291
+ flag of the same name — that one flags events in the proxy log; this one only
292
+ annotates a single command's own result.
293
+
294
+ The hint performs no extra work: it never runs `EXPLAIN`, reads a schema, or
295
+ issues a second request. It is suppressed entirely under `--recovery`, so the
296
+ recovery envelope keeps its exact machine contract.
297
+
298
+ - `--format table` appends `Performance hint: <recommendation>` to the footer.
299
+ - `--format json` adds `metadata.performanceAdvisory`:
300
+
301
+ ```json
302
+ {
303
+ "metadata": {
304
+ "statement": "SELECT",
305
+ "performanceAdvisory": {
306
+ "code": "SLOW_QUERY",
307
+ "executionTimeMs": 1250,
308
+ "thresholdMs": 1000,
309
+ "recommendation": "Review safely with: dbcli guide slow-query --format markdown. This hint runs no additional database diagnostics."
310
+ }
311
+ }
312
+ }
313
+ ```
314
+
315
+ The recommendation is engine-aware: PostgreSQL, MySQL, MariaDB, and Redis are
316
+ pointed at `dbcli guide slow-query`, because that goal resolves to real
317
+ diagnostic snippets for them. MongoDB and Elasticsearch ship no snippet for its
318
+ intents, so their hint states the timing and says so instead of naming a command
319
+ that would come back empty. `csv` and `html` output are unchanged.
320
+
226
321
  Below `admin`, SQL holding more than one statement is rejected, because only the
227
322
  first statement would decide the permission check while a driver on the simple
228
323
  query protocol executes them all. Semicolons inside string literals, backtick
@@ -526,12 +621,15 @@ dbcli q @analytics/revenue --param days=30 --format html > report.html
526
621
  - `--ui` — open the rendered HTML dashboard in the system browser (implies `--format html`; writes to a temp file then invokes `open` / `xdg-open` / `start`)
527
622
  - `--param <key=value>` — pass a parameter (repeatable)
528
623
  - `--param-file <path>` — JSON object whose keys are param names
529
- - `--no-limit` — skip the `SELECT * FROM (…) AS _dbcli_guard LIMIT 1000` wrap
624
+ - `--no-limit` — skip the `SELECT * FROM (…) AS _dbcli_guard LIMIT 1001` wrap (the effective cap is 1000; one extra row is fetched to detect truncation)
530
625
  - `--dry-run` — print the bound SQL + values without executing
531
- - `--use <name>` — pick a v2 named connection
626
+ - `--slow-ms <number>` — passive slow-query hint threshold (default `1000`; `0` disables). Same contract as `query` — see "Passive slow-query hint" there
532
627
  - `--recovery` — emit a `RecoveryEnvelope` on failure (see `recover`)
533
628
  - `--verify` — run the snippet's verification assertions after execution (only if the snippet defines them)
534
629
 
630
+ `q` has no command-level `--use`. To run a snippet against a v2 named connection,
631
+ use the global form: `dbcli --use <name> q @<snippet>`.
632
+
535
633
  **Permission:** query-only+
536
634
 
537
635
  #### Snippet file format
@@ -655,8 +753,9 @@ Size guard: `LRANGE` / `ZRANGE` stop overridden when `< 0` or `> 1000`; `SCAN` /
655
753
  ##### MongoDB snippets
656
754
 
657
755
  File extension: `.mongodb.sql`. Frontmatter must declare `engine: mongodb` and
658
- `operation: find` or `operation: aggregate`. `target: <collection>` provides a default
659
- collection that `dbcli q --collection <name>` can override. The body is JSON: an object
756
+ `operation: find` or `operation: aggregate`. `target: <collection>` declares the
757
+ collection the snippet runs against; the CLI has no flag to override it, so a different
758
+ collection means a different snippet. The body is JSON: an object
660
759
  for `find` and an array for `aggregate`. Each `{{param}}` placeholder is JSON-encoded
661
760
  at substitution time — strings are quoted and escaped, so an attacker-supplied string
662
761
  cannot escape into operator position.
@@ -1077,6 +1176,178 @@ Both parameters are required. Keep each expansion as one quoted shell argument;
1077
1176
  never use `eval`, and consider `--execute` only after the plan and captured DDL
1078
1177
  have been reviewed.
1079
1178
 
1179
+ ### design
1180
+
1181
+ Author, validate, render, and review a version-controlled SQL database design
1182
+ kept beside the code as `dbcli.design.json`. Every subcommand is offline: none
1183
+ opens a database connection, executes DDL, or calls an LLM. `design init` is the
1184
+ only writer, and it writes only to the explicit `--output` path.
1185
+
1186
+ ```text
1187
+ dbcli design init --output <path> [--dialect <dialect>]
1188
+ dbcli design validate [--file <path>] [--format <format>]
1189
+ dbcli design render [--file <path>] [--format <format>]
1190
+ dbcli design diff (--against-cache | --against-orm <paths>) [options]
1191
+ dbcli design propose (--against-cache | --against-orm <paths>) [options]
1192
+ ```
1193
+
1194
+ ```bash
1195
+ # Writes only to this explicit, missing path; edit the starter before validating.
1196
+ dbcli design init --output ./dbcli.design.json --dialect postgresql
1197
+
1198
+ dbcli design validate --format json
1199
+ dbcli design render --format mermaid
1200
+ dbcli design diff --against-cache --format markdown
1201
+ dbcli design diff --against-orm ./prisma/schema.prisma --format markdown
1202
+ dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
1203
+ ```
1204
+
1205
+ | Option | Applies to | Default | Meaning |
1206
+ |---|---|---|---|
1207
+ | `--output <path>` | `init` | required | Destination for the new artifact; refuses to overwrite an existing file. |
1208
+ | `--dialect <postgresql\|mysql\|mariadb>` | `init` | `postgresql` | Target SQL dialect recorded in the artifact. |
1209
+ | `--file <path>` | all but `init` | `dbcli.design.json` | Design artifact to read. |
1210
+ | `--format <format>` | all but `init` | see below | `validate`/`propose`: `json`, `markdown`. `render`: `json`, `markdown`, `mermaid` (default `markdown`). `diff`: `json` (default), `table`, `markdown`. |
1211
+ | `--against-cache` | `diff`, `propose` | off | Compare with the local schema cache; requires a configured PostgreSQL/MySQL/MariaDB connection whose system matches the artifact dialect, and a non-empty cache (run `dbcli schema` first). |
1212
+ | `--against-orm <paths>` | `diff`, `propose` | none | Compare with local ORM definition(s); repeatable or comma-separated, DDL paths support globs. Needs no config and no connection. |
1213
+ | `--orm-format <format>` | `diff`, `propose` | auto-detect | Force `prisma`, `ddl`, `json`, `drizzle`, `typeorm`, or `sequelize`. |
1214
+ | `--ignore <globs>` | `diff`, `propose` | none | Comma-separated table globs excluded from drift. |
1215
+
1216
+ `diff` and `propose` require **exactly one** comparison target; passing both or
1217
+ neither is an error.
1218
+
1219
+ #### Artifact shape
1220
+
1221
+ This example validates clean (0 errors, 0 warnings):
1222
+
1223
+ ```json
1224
+ {
1225
+ "version": 1,
1226
+ "dialect": "postgresql",
1227
+ "models": [
1228
+ {
1229
+ "name": "orders",
1230
+ "table": "orders",
1231
+ "description": "Completed purchases.",
1232
+ "fields": [
1233
+ { "name": "id", "type": "bigint", "nullable": false, "primaryKey": true, "unique": true },
1234
+ { "name": "customer_id", "type": "bigint", "nullable": false },
1235
+ { "name": "created_at", "type": "timestamptz", "nullable": false }
1236
+ ],
1237
+ "indexes": [
1238
+ { "name": "orders_customer_idx", "columns": ["customer_id", "created_at"], "unique": false }
1239
+ ]
1240
+ },
1241
+ {
1242
+ "name": "customers",
1243
+ "table": "customers",
1244
+ "fields": [
1245
+ { "name": "id", "type": "bigint", "nullable": false, "primaryKey": true, "unique": true }
1246
+ ]
1247
+ }
1248
+ ],
1249
+ "relationships": [
1250
+ {
1251
+ "name": "orders-customer",
1252
+ "from": { "model": "orders", "field": "customer_id" },
1253
+ "to": { "model": "customers", "field": "id" },
1254
+ "cardinality": "many-to-one"
1255
+ }
1256
+ ],
1257
+ "accessPatterns": [{ "model": "orders", "filters": ["customer_id"], "sort": ["created_at"] }],
1258
+ "decisions": [{ "name": "single-currency", "rationale": "Amounts are stored in minor units, USD only." }]
1259
+ }
1260
+ ```
1261
+
1262
+ It holds no SQL, credentials, rows, or provider configuration. `design init`
1263
+ emits this envelope with empty `models`, `relationships`, `accessPatterns`, and
1264
+ `decisions`.
1265
+
1266
+ #### Naming and limits
1267
+
1268
+ Two different naming rules apply, and mixing them up is the most common way an
1269
+ artifact fails before any review rule runs.
1270
+
1271
+ | Applies to | Rule |
1272
+ |---|---|
1273
+ | `models[].name`, `relationships[].name`, `relationships[].from/to.model`, `accessPatterns[].model`, `decisions[].name` | lowercase kebab-case, `^[a-z][a-z0-9-]*$` — underscores are rejected |
1274
+ | `models[].table`, `fields[].name`, `indexes[].name`, `indexes[].columns[]`, `filters[]`, `sort[]` | SQL identifier, `^[A-Za-z_][A-Za-z0-9_]*$` |
1275
+
1276
+ Relationship endpoints reference a **model name**, not a table name. Every object
1277
+ is strict: an unknown key is an error, not ignored. `description` and `rationale`
1278
+ are 1–1000 characters and must not contain SQL keywords or a connection string —
1279
+ "rows we delete after 30 days" is rejected for the word `delete`. `fields[].type`
1280
+ is at most 100 characters with no `;` or newline. `primaryKey`, `unique`,
1281
+ `indexes`, `filters`, `sort`, `relationships`, `accessPatterns`, and `decisions`
1282
+ may all be omitted.
1283
+
1284
+ Limits: file 256 KiB, 100 models, 100 fields per model, 200 relationships,
1285
+ 200 access patterns, 100 decisions, 1–16 columns per index, ≤16 entries in
1286
+ `filters` and `sort`.
1287
+
1288
+ #### Review findings
1289
+
1290
+ `validate` is fail-closed: any `error` finding exits `1`, and `render`, `diff`,
1291
+ and `propose` refuse to do their work while errors remain.
1292
+
1293
+ Structural problems — malformed JSON, an unknown key, a naming or type violation,
1294
+ a missing file, or a file over 256 KiB — are rejected before review runs and are
1295
+ reported as a single `INVALID_ARTIFACT` finding (`error`) whose `path` points at
1296
+ the offending JSON location. None of the codes below appear in that case.
1297
+
1298
+ | Severity | Codes |
1299
+ |---|---|
1300
+ | `error` | `NO_MODELS`, `DUPLICATE_MODEL`, `DUPLICATE_TABLE`, `DUPLICATE_FIELD`, `PRIMARY_KEY_COUNT`, `NULLABLE_PRIMARY_KEY`, `UNKNOWN_INDEX_FIELD`, `DUPLICATE_RELATIONSHIP`, `REVERSE_RELATIONSHIP`, `UNKNOWN_RELATIONSHIP_MODEL`, `UNKNOWN_RELATIONSHIP_FIELD`, `RELATIONSHIP_TYPE_MISMATCH`, `MANY_TO_MANY_REQUIRES_BRIDGE`, `ONE_TO_ONE_REQUIRES_UNIQUE_FK`, `UNKNOWN_ACCESS_MODEL`, `UNKNOWN_ACCESS_FIELD` |
1301
+ | `warn` | `DUPLICATE_INDEX`, `REDUNDANT_PRIMARY_KEY_INDEX`, `PREFIX_REDUNDANT_INDEX`, `ACCESS_PATTERN_INDEX` |
1302
+
1303
+ `REVERSE_RELATIONSHIP` fires when the same endpoints are declared again in the
1304
+ opposite direction; `PREFIX_REDUNDANT_INDEX` fires when a non-unique index is a
1305
+ leading-column prefix of a longer index. `v1` requires exactly one primary-key
1306
+ field per model and an explicit bridge model for `many-to-many`.
1307
+
1308
+ #### `design propose` (review-only)
1309
+
1310
+ `propose` turns drift into a plan a human reviews; it never applies a write. Each
1311
+ entry carries a `safety` of `dry-run` (an existing `migrate` command can represent
1312
+ the change losslessly) or `migration-review` (everything else), plus `preflight`,
1313
+ `rollback`, and `verification` steps:
1314
+
1315
+ ```json
1316
+ {
1317
+ "table": "orders",
1318
+ "object": "total_cents",
1319
+ "safety": "migration-review",
1320
+ "commands": ["..."],
1321
+ "preflight": [
1322
+ "dbcli blacklist list",
1323
+ "Confirm the exact affected table with: dbcli schema <exact-table> --format json"
1324
+ ],
1325
+ "rollback": "Capture the current schema and generated DDL before any approved write; define the inverse migration before execution.",
1326
+ "verification": [
1327
+ "After an approved write, run: dbcli schema <exact-table> --format json",
1328
+ "Re-run this same design diff command and review the remaining drift."
1329
+ ]
1330
+ }
1331
+ ```
1332
+
1333
+ **Workflows:**
1334
+
1335
+ - **New project** — `design init` → edit the artifact → `design validate` →
1336
+ `design render`. If application models already exist, use the offline
1337
+ `design diff --against-orm <path>` to reconcile the artifact and the ORM before
1338
+ any database exists.
1339
+ - **Existing database** — `blacklist list` → refresh the cache with
1340
+ `schema --format json` → `design diff --against-cache` →
1341
+ `design propose --against-cache`. Review the plan, perform any approved
1342
+ migration separately, then refresh the schema and rerun the same diff.
1343
+
1344
+ **Exit codes:** `0` when no errors, `1` when the artifact has review errors, an
1345
+ invalid target selection, an unreadable file, or reported drift errors.
1346
+
1347
+ An external coding agent may draft the artifact, but a human should review it
1348
+ before it is relied upon. Do not create or rewrite `dbcli.design.json` without an
1349
+ explicit human request.
1350
+
1080
1351
  ### snapshot
1081
1352
 
1082
1353
  Capture a **result fingerprint** of a query (not schema): `rowCount` plus per-column
@@ -1128,7 +1399,7 @@ Opt-in flag trio that persists a **VerificationArtifact JSON** (schema v1) under
1128
1399
  | Flag | Required | Description |
1129
1400
  | :--- | :--- | :--- |
1130
1401
  | `--write-verification-artifact` | opt-in | Trigger artifact write. No-op when no verdict has been produced. |
1131
- | `--verification-subject <kind:name>` | yes (when flag is set) | Subject identifier. Format: `<kind>:<name>`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `manual`. |
1402
+ | `--verification-subject <kind:name>` | yes (when flag is set) | Subject identifier. Format: `<kind>:<name>`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `table`, `manual`. |
1132
1403
  | `--verification-summary <text>` | no | Free-text summary line stored in the artifact. Default when pass: "Assertion verified the expected state." Default when fail: "Assertion did not verify the expected state." |
1133
1404
 
1134
1405
  **Output contract:**
@@ -1390,7 +1661,7 @@ Examples:
1390
1661
 
1391
1662
  Boundaries:
1392
1663
  - Recovery only **suggests** commands; agents (or humans) execute them. No automatic remediation in v1.15.0.
1393
- - As of v1.16.0, `--recovery` is honored on `query`, `q`, `insert`, `update`, `delete`, `export`, `schema`, and `inspect`. Other commands (`report`, `guide`, `doctor`, `migrate`, `init`, `use`, `status`, `list`, `check`, `diff`, `plan`, `shell`, `blacklist`, `completion`, `upgrade`, `skill`) keep their existing error behavior.
1664
+ - `--recovery` is honored on `query`, `q`, `insert`, `update`, `delete`, `export`, `schema`, `inspect`, `lint`, and `diff`. Other commands (`report`, `guide`, `doctor`, `migrate`, `init`, `use`, `status`, `list`, `check`, `plan`, `shell`, `blacklist`, `completion`, `upgrade`, `skill`) keep their existing error behavior.
1394
1665
  - `dbcli inspect --require-schema-cache` throws `SCHEMA_CACHE_MISSING` when the active SQL connection has no usable schema cache. Combine with `--recovery` for the structured envelope.
1395
1666
  - `BLACKLIST_COLUMN_WRITE` and `PERMISSION_DENIED` envelopes prepend a `risk: 'dry-run'` step (e.g. `dbcli insert <table> --dry-run`) when the failing operation was an INSERT / UPDATE / DELETE.
1396
1667
  - Recovery steps reuse the v1.14.0 `GuideStep` shape, including the full `risk` enum (`readonly` / `dry-run` / `write` / `unknown`).
@@ -1424,7 +1695,7 @@ Boundaries:
1424
1695
  |---|---|---|
1425
1696
  | `readonly` | local read-only | `dbcli inspect`, `dbcli doctor`, `dbcli blacklist list`, `dbcli schema <table>` |
1426
1697
  | `dry-run` | write subcommand invoked with `--dry-run` | `dbcli update orders --where id=1 --dry-run`, `dbcli q @x --dry-run` |
1427
- | `local-write` | writes local config / cache / blacklist | `dbcli blacklist remove <table>`, `dbcli use <name>`, `dbcli schema --refresh` |
1698
+ | `local-write` | writes local config / cache / blacklist | `dbcli blacklist table remove <table>`, `dbcli use <name>`, `dbcli schema --refresh` |
1428
1699
  | `db-write` | mutates the connected database | `dbcli update orders --where id=1 --set …` (no `--dry-run`), `dbcli q @x` (no `--dry-run`) |
1429
1700
  | `interactive` | requires TTY | `dbcli init`, `dbcli init --force` |
1430
1701
 
@@ -1577,7 +1848,7 @@ dbcli recover --next --after-step 1 --result '{"status":"ok"}' --format markdown
1577
1848
 
1578
1849
  (v1.20.0+) Inspect, query, and manage the per-connection audit log written to `.dbcli/audit/<connection>.jsonl`.
1579
1850
 
1580
- Audit entries are metadata-only by design — never raw SQL bodies, `--param` values, or result cell contents (D3 lock). Redaction is sourced from `tests/helpers/sensitive-output.ts` (same source as `inspect` / `guide` / `recover` agent contracts).
1851
+ Audit entries are metadata-only by design — never raw SQL bodies, `--param` values, or result cell contents (D3 lock). Redaction is sourced from `src/utils/redaction.ts` (same source as `inspect` / `guide` / `recover` agent contracts).
1581
1852
 
1582
1853
  #### Subcommands
1583
1854
 
@@ -1614,7 +1885,9 @@ Examples:
1614
1885
  | `<id-prefix>` | Positional. UUID or prefix ≥ 4 characters; ambiguous prefix exits 1 with disambiguation hint; prefix < 4 chars exits 1. | — |
1615
1886
  | `--recovery-ref <id>` | Find the audit entry whose `recovery_ref` field matches this id (exact, not prefix). Mutually exclusive with positional `<id-prefix>` (D-38). | — |
1616
1887
  | `--all` | Search across all connections. Output is an envelope `{ connection, entry }` (single-hit also envelope, for shape stability — D-36). | off |
1617
- | `--no-brief` | Disable brief mode when a higher-level default enables it. | off |
1888
+ | `--brief` | Trim `metadata` and `redacted_query` from the entry. | off |
1889
+ | `--for-agent` | Shortcut for `--format json --brief`. | off |
1890
+ | `--no-brief` | Disable brief mode when a higher-level default enables it (e.g. `--for-agent`). | off |
1618
1891
  | `--format <fmt>` | `table` \| `json`. | `table` |
1619
1892
 
1620
1893
  Examples:
@@ -1648,7 +1921,7 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
1648
1921
  #### Boundaries
1649
1922
 
1650
1923
  - Entries are append-only JSONL; rotation triggers at `~10 MB` or `~1000` entries (whichever first). Previous segment is preserved as `.jsonl.1`.
1651
- - Bi-directional `recovery_ref` / `audit_ref` linkage is wired on every command that accepts `--recovery`: `query`, `inspect`, `insert`, `update`, `delete`, `export`, `q`, and `schema`. Use `audit tail --recovery-ref <id>` to find the audit entry an envelope was emitted alongside.
1924
+ - Bi-directional `recovery_ref` / `audit_ref` linkage is wired on every command that accepts `--recovery`: `query`, `inspect`, `insert`, `update`, `delete`, `export`, `q`, and `schema`. Use `audit show --recovery-ref <id>` to find the audit entry an envelope was emitted alongside.
1652
1925
  - Audit writer failures are non-fatal (D6): main command result and exit code are preserved; a stderr warning is emitted. `audit health` surfaces the failure reason.
1653
1926
  - Reader truncation tolerance: a crash-truncated last line is skipped with a stderr warn `[dbcli audit] skipping truncated last line in <file>`; a mid-file non-JSON line is treated as corruption, exits 1, and points at `dbcli audit clear`.
1654
1927
 
@@ -1909,7 +2182,7 @@ dbcli verification list --include-invalid --format json
1909
2182
  | `--format <json\|table>` | Output format. | `json` |
1910
2183
  | `--limit <n>` | Maximum number of entries to return. | `20` |
1911
2184
  | `--status <status>` | Filter by status. One of: `verified`, `not_verified`, `indeterminate`, `blocked`. | all |
1912
- | `--subject <kind[:name]>` | Filter by subject kind or exact `kind:name`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `manual`. | all |
2185
+ | `--subject <kind[:name]>` | Filter by subject kind or exact `kind:name`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `table`, `manual`. | all |
1913
2186
  | `--include-invalid` | Surface malformed artifact files (normally skipped silently). Invalid files are returned as a separate top-level `invalid` array in JSON output, each entry shaped `{ "path": "...", "filename": "...", "error": "..." }`. When off, `invalid` is `[]`. | off |
1914
2187
 
1915
2188
  **Missing directory:** if `.dbcli/verification/` does not exist, exits `0` with an
@@ -2023,6 +2296,7 @@ includes `storageDir`, `dryRun`, `cutoff`, `criteria`, `protected`, `candidates`
2023
2296
  | `assertion` | General-purpose inline assertions. |
2024
2297
  | `migration` | Schema migration pre/post checks. |
2025
2298
  | `backfill` | Data backfill verification assertions. |
2299
+ | `table` | `verify constraint` artifacts — the subject name is the table checked. |
2026
2300
  | `manual` | Manually triggered or ad-hoc verification runs. |
2027
2301
 
2028
2302
  **Storage root:** `<cwd>/.dbcli/verification/` (cwd-relative; independent of `--config`).
@@ -2855,9 +3129,9 @@ Permission is derived from the command's first token (case-insensitive). Unknown
2855
3129
 
2856
3130
  | Tier | Commands |
2857
3131
  |------|----------|
2858
- | `query-only` | `GET`, `MGET`, `STRLEN`, `EXISTS`, `TTL`, `PTTL`, `TYPE`, `SCAN`, `HGET`, `HGETALL`, `HKEYS`, `HVALS`, `HLEN`, `HEXISTS`, `HMGET`, `LRANGE`, `LLEN`, `LINDEX`, `SMEMBERS`, `SCARD`, `SISMEMBER`, `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE`, `ZCARD`, `ZSCORE`, `PING`, `ECHO` |
2859
- | `read-write` | `SET`, `SETEX`, `SETNX`, `PSETEX`, `MSET`, `MSETNX`, `APPEND`, `INCR`/`INCRBY`, `DECR`/`DECRBY`, `HSET`/`HSETNX`/`HMSET`/`HINCRBY`, `LPUSH`/`RPUSH`/`LPOP`/`RPOP`/`LSET`, `SADD`/`SREM`, `ZADD`/`ZREM`, `EXPIRE`/`EXPIREAT`/`PEXPIRE`/`PERSIST`, `RENAME` |
2860
- | `data-admin` | `DEL`, `UNLINK`, `HDEL` |
3132
+ | `query-only` | `GET`, `MGET`, `STRLEN`, `EXISTS`, `TTL`, `PTTL`, `TYPE`, `SCAN`, `HGET`, `HGETALL`, `HKEYS`, `HVALS`, `HLEN`, `HEXISTS`, `HMGET`, `LRANGE`, `LLEN`, `LINDEX`, `SMEMBERS`, `SCARD`, `SISMEMBER`, `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE`, `ZCARD`, `ZSCORE`, `XLEN`, `XREAD`, `XRANGE`, `XREVRANGE`, `PING`, `ECHO` |
3133
+ | `read-write` | `SET`, `SETEX`, `SETNX`, `PSETEX`, `MSET`, `MSETNX`, `APPEND`, `INCR`/`INCRBY`, `DECR`/`DECRBY`, `HSET`/`HSETNX`/`HMSET`/`HINCRBY`, `LPUSH`/`RPUSH`/`LPOP`/`RPOP`/`LSET`/`LREM`, `SADD`/`SREM`, `ZADD`/`ZREM`, `XADD`, `EXPIRE`/`EXPIREAT`/`PEXPIRE`/`PERSIST`, `RENAME` |
3134
+ | `data-admin` | `DEL`, `UNLINK`, `HDEL`, `XDEL` |
2861
3135
  | `admin` | `FLUSHDB`, `FLUSHALL`, `CONFIG`, `INFO`, `CLIENT`, `DEBUG`, `SHUTDOWN`, `KEYS`, `MONITOR`, `SAVE`, `BGSAVE`, `BGREWRITEAOF`, `REPLICAOF`, `SLAVEOF`, `ACL` |
2862
3136
 
2863
3137
  ### Schema inspection
@@ -3068,5 +3342,5 @@ GET /orders/_search
3068
3342
 
3069
3343
  - Writes (`insert`/`update`/`delete`) are not exposed yet — the adapter implements them, but the CLI currently only routes them for SQL and MongoDB. Read-only `export` (v1.22) and the interactive `shell` (v1.22) are available.
3070
3344
  - No `_search/scroll` or PIT pagination at the CLI layer; large pulls need a saved external script.
3071
- - `check`, `diff`, `migrate`, and `q` are SQL-only and exit with errors (or fall through to a generic "unsupported" path).
3345
+ - `check`, `diff`, and `migrate` are SQL-only and exit with errors (or fall through to a generic "unsupported" path). `q` **is** supported — Elasticsearch snippets use the `.elasticsearch.sql` extension (see `@diag/es-cluster-health`).
3072
3346
  - Blacklist column rules are applied to flattened hit rows on `query`; table-level blacklist rejects an index up front.