@carllee1983/dbcli 1.37.0 → 1.38.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.
@@ -12,65 +12,54 @@ If the `dbcli` executable is not available in `PATH`, use
12
12
  fallback for Codex plugin installs where the skill is installed by the plugin but
13
13
  the CLI package has not been installed globally.
14
14
 
15
- ## AI agent workflow (follow in order)
16
-
17
- 0. `dbcli skill context --format xml` LLM prompt context payload: serializes connection metadata, schema caches, and saved queries into a compressed XML/JSON structure for prompt injection.
18
- 1. `dbcli inspect --for-agent` — bounded snapshot: connection, permission, blacklist, objects, snippets, suggested next commands.
19
- 2. `dbcli report --format json` — diagnostic report (health/capacity/perf) using built-in snippets.
20
- 3. `dbcli guide <goal> --format json` — deterministic next-command plan for a fixed goal (`slow-query`, `capacity`, `health`, `index-usage`, `permissions`, `schema-overview`). Use `dbcli guide --list` to see goals.
21
- 4. `dbcli recovery --code <CODE>` — look up structured recovery commands for a known error code (e.g. `CONN_REFUSED`, `PERMISSION_DENIED`, `SNIPPET_NOT_FOUND`). Pass `--recovery` to `dbcli query` / `dbcli q` to have failures emit a `RecoveryEnvelope` directly. In v1.16.0 the `--recovery` flag is also accepted by `dbcli insert`, `dbcli update`, `dbcli delete`, `dbcli export`, `dbcli schema`, and `dbcli inspect` (which also gained `--require-schema-cache` for the `SCHEMA_CACHE_MISSING` path).
22
- - **v1.17.0** `dbcli recover` reads the auto-saved envelope (`.dbcli/last-recovery.json`) written by any prior `--recovery` failure. Inspect it (Markdown by default) or pass `--apply` to execute the saved plan under risk gating.
23
- - **v1.17.0** `dbcli recover --apply` runs `risk=readonly` and `risk=dry-run` steps by default. Open the gate one tier with `--allow-write=readonly-cmd` (run local-side writes such as `blacklist remove`) or `--allow-write=write-cmd` (also run steps that mutate the connected database). Pass `--from <file>` to read an explicit envelope instead of the auto-saved one. Use `--format json` for an aggregated machine-readable result.
24
- - Exit codes: `0` ok, `1` step failed, `2` envelope missing/malformed, `3` every step skipped (open `--allow-write` or fix interactive/placeholder).
25
- - GuideStep optional fields agents should respect:
26
- - `interactive: true` — step requires a TTY (`dbcli init` family). `dbcli recover --apply` skips with `skipped:interactive`.
27
- - `dbWrite: true` — step mutates the connected database. Gates the highest risk tier; reserved for future write-side recovery steps.
28
- - `placeholders: ['<token>', ...]` — agent must replace these tokens before `--apply` will execute. Skipped with `skipped:placeholder`.
29
- - **v1.17.0 P4 Verification.** After `--apply` finishes the main plan, dbcli runs **one extra read-only step** (`envelope.verify`) to probe whether the original failure is gone. The output gains `verifyResult` (the executed step) and `verifyStatus`:
30
- - `passed` verifier exited 0 and (where applicable) the expected JSON shape was found.
31
- - `failed` — verifier exited non-zero or timed out.
32
- - `indeterminate` verifier exited 0 but the heuristic could not confirm the fix (JSON parse failure, missing field, gate skip).
33
- Verify is **only run when** `finalStatus === 'ok'`. Pass `--no-verify` to skip it. Heuristic is intentionally cheap; agents should still re-run their own check against the original failing operation when correctness matters.
34
-
35
- Verification outcome vocabulary: use `verified` only when required evidence matched;
36
- use `not_verified` when the check ran and contradicted the expected state; use
37
- `indeterminate` when the check ran but evidence was ambiguous; use `blocked` when
38
- verification could not run because of config, permission, schema, placeholder, or
39
- safety gates.
40
-
41
- - **v1.17.0 P2 Multi-turn `--next`.** When `--apply` is too coarse — interactive blocks it, the plan needs per-step inspection, or the agent wants to drive recovery with its own tools — execute steps one at a time and ask dbcli for the next:
42
-
43
- ```bash
44
- # The agent reads step 1 from the envelope, runs it, then asks dbcli for step 2:
45
- dbcli recover --next --after-step 1 --result '{"status":"ok","exitCode":0}'
46
- # Returns a NextResult envelope:
47
- # {
48
- # "schemaVersion": 1,
49
- # "kind": "step",
50
- # "errorCode": "BLACKLIST_TABLE",
51
- # "cursor": 2,
52
- # "totalSteps": 3,
53
- # "step": { "order": 2, "command": "dbcli inspect --for-agent", ... }
54
- # }
55
- # After the last step, dbcli returns kind: "done".
56
- ```
57
-
58
- `--result` accepts inline JSON `StepResultSummary` or `@<path>` to read from a file. `stdoutSummary` and `stderrSummary` are capped at 4 KB each — pre-truncate to the **last** 4 KB before passing. `--next` is mutually exclusive with `--apply`. Each call is independent (no persisted cursor) — the agent tracks `--after-step` itself.
59
-
60
- **Connection branching.** For `CONN_*` codes, the envelope ships a `branches` map + `branchFork` descriptor. Step 1 (`dbcli doctor --format json`) is the fork point: pass the doctor JSON in `--result.stdoutSummary` and `--next` will pick one of four labeled branches (`doctor-clean` / `doctor-config-missing` / `doctor-auth-error` / `doctor-network-error`). NextResult then carries `branchId` and `branchDescription`; subsequent calls must echo `--branch <id>` to walk that branch. Parse failure / unmatched keywords fall back to linear `recovery`. `--apply` ignores branches entirely.
61
- 5. `dbcli blacklist list` — sensitive data boundaries.
62
- 6. `dbcli schema <table> --format json` — real column names (SQL/Mongo/ES) or `schema <key>` (Redis). **Never guess.**
63
- 7. Run `query` / `insert` / `update` / `delete` / `export` within permission.
64
- 8. All writes: `--dry-run` (SQL/Mongo) → run → `query` read-back to confirm.
65
- - **v1.21.0 Self-Verification Loops**: If a snippet defines a `verify` block in its frontmatter, run the snippet with `dbcli q @name --verify` to automatically run primary changes, execute the verification query, and validate assertions.
15
+ ## How to use dbcli
16
+
17
+ **Safety baselineapply to every operation:**
18
+
19
+ 1. `dbcli blacklist list` — confirm sensitive-data boundaries.
20
+ 2. `dbcli schema <object> --format json` — confirm real column/field names. **Never guess.**
21
+ 3. All writes: `--dry-run` (SQL/Mongo) run `query` read-back to confirm.
22
+
23
+ > `report` and `guide` already embed an `inspect` snapshot you do **not** need to run
24
+ > `dbcli inspect` first. Run `dbcli inspect --for-agent` manually only when you want the
25
+ > audit-recent context or to diagnose a connection problem.
26
+
27
+ **Then route by task:**
28
+
29
+ | Task | Path |
30
+ | --- | --- |
31
+ | A named workflow fits ("diagnose slow query", "audit permissions") | `skill tasks list` → `skill tasks plan <pack>` **prefer this; do not invent steps** |
32
+ | A fixed diagnostic goal | `guide <goal>` (`slow-query` / `capacity` / `health` / `index-usage` / `permissions` / `schema-overview`; `guide --list`) |
33
+ | Setting up a connection | see **Connection setup** |
34
+ | Anything else | run commands manually; consult the **Developer workflows** cheat-sheet |
35
+
36
+ Slow-query diagnosis has three canonical paths (pick by what you already know):
37
+
38
+ - Known slow SQL `skill tasks plan diagnose-slow-query --param query="<SQL>"` → `guide missing-index-for "<SQL>"`
39
+ - Known hot table → `skill tasks plan analyze-table-perf --param table=<table>`
40
+ - Whole-environment scan → `report --section perf` → `guide slow-query`
41
+
42
+ `report --section perf` already runs the slow-query, index-usage, and cache-hit diagnostics —
43
+ afterwards add only the `@diag/*` it does not cover (`missing-indexes`, `locks`, `connections`,
44
+ `table-sizes`). Once you have a specific slow statement, `explain --analyze "<SQL>"` shows its plan.
45
+
46
+ **On failure:** pass `--recovery` to `query` / `q` / `insert` / `update` / `delete` /
47
+ `export` / `schema` / `inspect`. The command emits a `RecoveryEnvelope` to stdout and saves
48
+ it to `.dbcli/last-recovery.json`; then `dbcli recover` inspects it and `dbcli recover --apply`
49
+ runs the saved plan under risk gating. Multi-turn `--next`, connection branching, and the
50
+ post-apply verify probe are documented in reference.md §Recovery Cookbook.
51
+
52
+ When reporting a check's outcome use the vocabulary `verified` (evidence matched) /
53
+ `not_verified` (check ran and contradicted) / `indeterminate` (ran but ambiguous) /
54
+ `blocked` (could not run due to config, permission, schema, placeholder, or safety gate).
66
55
 
67
56
  Prefer `--format json` for agent-friendly output.
68
57
 
69
58
  ## Agent Task Packs
70
59
 
71
- When the user asks for a database workflow (e.g. "diagnose this slow query", "audit
72
- permissions", "review long-running operations"), prefer published task templates
73
- over inventing steps from memory.
60
+ When the user asks for a database workflow ("diagnose this slow query", "audit
61
+ permissions", "review long-running operations"), **prefer published task templates over
62
+ inventing steps from memory.**
74
63
 
75
64
  ```bash
76
65
  dbcli skill tasks list --format json # discover
@@ -78,45 +67,34 @@ dbcli skill tasks show <task> # inspect
78
67
  dbcli skill tasks plan <task> --param key=value --format json # generate plan
79
68
  ```
80
69
 
81
- The plan output is an ordered list of dbcli commands with rationale and risk
82
- labels. Execute them one at a time — task plans do **not** override blacklist,
83
- schema, dry-run, or confirmation requirements.
84
-
85
- Builtin packs: `diagnose-slow-query` and **(v1.23)** `analyze-table-perf` — a
86
- read-only `plan-only` pack taking a required `table` parameter that walks
87
- `blacklist list` `schema <table> --format json` → `guide index-usage`. `dbcli
88
- inspect` suggests `analyze-table-perf` automatically for the hottest table in
89
- recent audit activity. Additional read-only packs: `audit-permissions`,
90
- `safe-backfill`, `schema-drift-review`, `connection-health` run
91
- `dbcli skill tasks list` for the full set.
92
-
93
- Review & verification packs: `pr-database-review` (assess a PR's changed queries,
94
- migrations and blacklist risk), `migration-review` (capture pre-change schema and
95
- preview DDL), `safe-backfill-verify` (backfill planning with a read-back `assert`),
96
- and `slow-endpoint-investigation` (chain `proxy analyze` → `explain` →
97
- `guide missing-index-for`). All are read-only `plan-only` — pick the pack matching the
98
- user's situation before improvising, and run any index/DDL proposal through
99
- `migration-review` before writing.
70
+ The plan is an ordered list of dbcli commands with rationale and risk labels. Execute them
71
+ one at a time — task plans do **not** override blacklist, schema, dry-run, or confirmation
72
+ requirements.
73
+
74
+ Builtin packs: `diagnose-slow-query` (targets a specific SQL), `analyze-table-perf` (targets
75
+ a specific table; `dbcli inspect` auto-suggests it for the hottest table in recent audit
76
+ activity), `audit-permissions`, `safe-backfill`, `schema-drift-review`, `connection-health`.
77
+ Review/verify packs: `pr-database-review`, `migration-review`, `safe-backfill-verify`,
78
+ `slow-endpoint-investigation`. All are read-only `plan-only` — pick the pack matching the
79
+ situation, and run any index/DDL proposal through `migration-review` before writing.
100
80
 
101
81
  Tasks live under `assets/tasks/` (builtin), `.dbcli-shared/tasks/` (shared), and
102
82
  `.dbcli/tasks/` (local override).
103
83
 
104
84
  ## Developer workflows
105
85
 
106
- Use these workflows when database impact is implicit in a development task. Keep
107
- the normal dbcli safety rules: prefer `--format json`, run `blacklist list`
108
- before touching sensitive data, confirm names with `schema`, dry-run writes, and
109
- use `--recovery` / `recover` after failures.
110
-
111
- | Situation | Use dbcli for | Minimum safe path |
112
- | --- | --- | --- |
113
- | DB-backed feature | Map product/code terms to real objects before editing code. | `inspect --for-agent` -> `blacklist list` -> `schema <object>` -> `queries suggest <intent>` |
114
- | Application data bug | Separate stored facts from application-code inference. | `inspect --for-agent` -> `audit tail --for-agent --n 10` -> `blacklist list` -> `schema <object>` -> narrow query/snippet |
115
- | ORM or migration work | Ground model and migration edits in live schema evidence. | `schema --format json` -> `diff --snapshot <name>` -> generate DDL via `migrate add-index`/`add-column` (preview SQL) -> `diff --against <snapshot>` |
116
- | PR database review | Check query, write, migration, export, fixture, and blacklist risk. | Review changed persistence paths, then propose concrete `schema`, `plan`, `dry-run`, `report`, or `guide` commands for each material claim. |
117
- | Slow endpoint or query | Prefer read-only diagnostics before index proposals. | `report --section perf` -> task pack `analyze-table-perf` -> `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
118
- | Safe data backfill | Scope affected rows and preview mutations before execution. | `blacklist list` -> `schema <object>` -> count/scope query -> `update ... --dry-run` -> read-back or snippet `--verify`. |
119
- | Environment validation | Check config shape and connectivity without leaking secrets. | `status --format json` -> `doctor --format json` -> `inspect --for-agent --no-connect --format json`. |
86
+ Use these workflows when database impact is implicit in a development task. The safety baseline
87
+ in **How to use dbcli** still applies.
88
+
89
+ | Situation | Minimum safe path |
90
+ | --- | --- |
91
+ | DB-backed feature | `blacklist list` `schema <object>` `queries suggest <intent>` |
92
+ | Application data bug | `audit tail --for-agent --n 10` → `blacklist list` → `schema <object>` → narrow query |
93
+ | ORM or migration work | `schema --format json` `diff --snapshot <name>` `migrate add-index`/`add-column` (preview SQL) `diff --against <snapshot>` |
94
+ | PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
95
+ | Slow endpoint or query | `report --section perf` task pack `analyze-table-perf` `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
96
+ | Safe data backfill | `blacklist list` `schema <object>` count/scope query `update --dry-run` read-back or snippet `--verify`. |
97
+ | Environment validation | `status --format json` `doctor --format json` `inspect --for-agent --no-connect`. |
120
98
 
121
99
  Copy-paste command anchors:
122
100
 
@@ -126,84 +104,43 @@ dbcli blacklist list --format json
126
104
  dbcli schema <object> --format json
127
105
  dbcli queries suggest <intent> --format json
128
106
  dbcli audit tail --for-agent --n 10
129
- dbcli schema --format json
130
107
  dbcli diff --snapshot <name>
131
- dbcli migrate add-index <table>
132
- dbcli diff --against <snapshot>
133
108
  dbcli report --section perf --format json
134
109
  dbcli skill tasks plan analyze-table-perf --param table=<table> --format json
135
110
  dbcli guide missing-index-for "<query>" --format json
136
- dbcli proxy analyze --format json
137
- dbcli query "<count/scope query>" --format json
138
111
  dbcli update <object> --where "<bounded predicate>" --set '<json>' --dry-run --format json
139
- dbcli status --format json
140
- dbcli doctor --format json
141
112
  dbcli inspect --for-agent --no-connect --format json
142
113
  ```
143
114
 
144
- Developer workflow guardrails:
115
+ Guardrails:
145
116
 
146
- - Never invent table, collection, key, index, or field names. Confirm them with
147
- `schema` before writing code that depends on them.
148
- - Separate database facts from application-code inference. Report which dbcli
149
- output shaped the code or review conclusion.
150
- - For writes and backfills, include scope count, dry-run preview, execution
151
- command, and read-back or snippet verification.
117
+ - Never invent table, collection, key, index, or field names. Confirm with `schema`.
118
+ - Separate database facts from application-code inference. Report which dbcli output shaped the conclusion.
119
+ - For writes and backfills, include scope count, dry-run preview, execution command, and read-back.
152
120
  - Do not create indexes directly from a performance suggestion; turn them into reviewed migrations.
153
121
  - Do not print credentials, copied connection strings, or blacklisted values.
154
- - To persist result evidence for a read-back assertion, run `assert ... --write-verification-artifact --verification-subject <kind:name>` (kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `manual`).
155
- - Inspect result evidence (read-only): `dbcli verification summary --format json`
156
- (also `verification list` / `verification show <id>`). Reclaim old artifacts with
157
- `dbcli verification prune --older-than 30d` (dry-run; add `--execute --force` to delete).
158
- - `tasks plan safe-backfill-verify` when the user needs a plan only.
159
- - `verify safe-backfill` — before a real safe backfill (preflight) and after it
160
- (`--after-write`) when durable evidence is required. Never executes the write.
161
- - `tasks plan migration-review` — when the user needs a migration plan only (plan output, no DDL executed).
162
- - `verify migration` — preflight a schema migration (analyze DDL, run guards) and after the migration is applied externally (`--after-write`) to record evidence. Never executes DDL.
163
- - `verification show <id>` — cite the final artifact.
164
-
165
- Full flags, per-command copy-paste blocks, `migrate` DDL, interactive `shell`, and MongoDB/Redis/ES walkthroughs are in [reference.md](reference.md) (installed next to this file).
166
-
167
- ## Audit Log usage
168
-
169
- Use the audit log when you need cross-session history or forensics on what dbcli
170
- has done on this database, rather than re-querying live DB state from scratch.
171
-
172
- **Scenario 1 — Session handoff (picking up where another agent left off):**
173
-
174
- ```bash
175
- dbcli audit tail --for-agent --n 10 # last 10 entries as JSON envelope
176
- dbcli audit tail --all --for-agent --n 20 # cross-connection merged view (D4)
177
- ```
122
+ - Durable evidence: `assert --write-verification-artifact --verification-subject <kind:name>`;
123
+ inspect with `verification summary` / `list` / `show <id>`. The `verify safe-backfill` /
124
+ `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>`
125
+ family runs preflight + `--after-write` checks and **never executes the write**. Full flags
126
+ and the per-command blocks are in reference.md.
178
127
 
179
- Returns an agent-facing JSON envelope with `session_id` / `engine` / `command` /
180
- `target` / `success` per entry. Metadata-only by design — never raw SQL bodies,
181
- `--param` values, or result cell contents (D3 lock).
128
+ ## Audit log
182
129
 
183
- **Scenario 2 Forensics (reconstructing a failure):**
130
+ Use the audit log for cross-session history or failure forensics instead of re-querying
131
+ live DB state.
184
132
 
185
133
  ```bash
186
- dbcli recover --format json # inspect audit_recent embed + recovery_ref
187
- dbcli audit show <id-prefix> # full entry by id prefix (>=4 chars)
188
- dbcli audit show --recovery-ref <envelope-id> # find entry that emitted an envelope
134
+ dbcli audit tail --for-agent --n 10 # last N entries (JSON envelope, metadata-only)
135
+ dbcli audit show <id-prefix> # full entry by id prefix (4 chars)
136
+ dbcli audit show --recovery-ref <env-id> # find the entry that emitted an envelope
189
137
  ```
190
138
 
191
- The `inspect` / `guide` / `recover` / `recover --apply` agent JSON output embeds
192
- `audit_recent: AuditEntryBrief[]` (last 5 entries) a fresh session has immediate
193
- history context. The envelope's `audit_ref` and the audit entry's `recovery_ref`
194
- point at each other; agents can pivot either direction.
195
-
196
- Bi-directional `recovery_ref` / `audit_ref` linkage is wired on every command
197
- that accepts `--recovery`: `query`, `inspect`, `insert`, `update`, `delete`,
198
- `export`, `q`, and `schema`. Agents can pivot from an envelope to its audit
199
- entry via `audit tail --recovery-ref <id>`.
200
-
201
- Audit entries are written to `.dbcli/audit/<connection>.jsonl` with rotation at
202
- ~10 MB or 1000 entries. `audit.enabled = false` in `.dbcli` opts out (default ON
203
- since v1.20.0). For flag reference see [`reference.md`](./reference.md) §audit.
204
- For end-to-end recovery walkthroughs (per-code scenarios, `--next` multi-turn,
205
- envelope ⇄ audit pivot, risk-gate cheat sheet) see
206
- [`reference.md`](./reference.md) §Recovery Cookbook.
139
+ The `inspect` / `guide` / `recover` agent JSON embeds `audit_recent` (last 5 entries) — a
140
+ fresh session has immediate history. An envelope's `audit_ref` and an audit entry's
141
+ `recovery_ref` point at each other, so you can pivot either way. Audit is on by default
142
+ (`audit.enabled = false` to opt out); entries are metadata-only (never SQL bodies, `--param`
143
+ values, or result cells) and rotate at ~10 MB / 1000 entries. Full flags: reference.md §audit.
207
144
 
208
145
  ## Quick start
209
146
 
@@ -234,12 +171,12 @@ or `doctor` / `status` reports a missing or invalid config, follow this flow.
234
171
  2. **Where do credentials live?**
235
172
  - Already in a `.env` (`DATABASE_URL` or `DB_HOST` / `DB_PORT` / `DB_USER` /
236
173
  `DB_PASSWORD` / `DB_NAME` | `DB_DATABASE`) → `init` parses it automatically.
237
- - Need to keep secrets out of `.dbcli` (CI/CD, multi-env) → `--use-env-refs`
238
- plus `--env-host` / `--env-port` / `--env-user` / `--env-password` / `--env-database`.
174
+ - Need to keep secrets out of `.dbcli` (CI/CD, multi-env) → `--use-env-refs` (see below).
239
175
  - Plain values are acceptable → pass `--host` / `--port` / `--user` /
240
176
  `--password` / `--name` (and `--system`).
241
177
  3. **What permission tier?** Default to the **lowest** that satisfies the task:
242
- `query-only` → `read-write` → `data-admin` → `admin`. Set with `--permission`.
178
+ `query-only` → `read-write` → `data-admin` → `admin`. Set with `--permission`
179
+ (defaults to `query-only`).
243
180
  4. **Verify, never assume.** After init: `dbcli status` (system + permission +
244
181
  blacklist summary, no creds) and `dbcli doctor --format json` (env, config
245
182
  shape, connectivity, schema-cache age, Mongo SRV path).
@@ -279,25 +216,38 @@ dbcli init --conn-name staging --env-file .env.staging --permission query-only
279
216
  dbcli init --conn-name prod --env-file .env.production --use-env-refs --skip-test
280
217
  dbcli use --list # show all, * marks default
281
218
  dbcli use prod # switch default
282
- dbcli query --use staging "SELECT 1" # one-shot override
219
+ dbcli query --use staging "SELECT 1" # one-shot override on any subcommand
283
220
  dbcli init --rename staging:stg # rename
284
221
  dbcli init --remove stg # remove
285
222
  ```
286
223
 
287
- Per-connection schema cache lives at `.dbcli/schemas/<connection>/`. Run
288
- `dbcli schema --use <name>` once per connection before `schema <table>` —
289
- otherwise the cache may serve another connection's columns.
224
+ Each named connection has its own schema cache at `.dbcli/schemas/<connection>/`. Run
225
+ `dbcli schema --use <name>` once per connection **before** `schema <table>` — otherwise the
226
+ cache may serve another connection's columns. `schema --refresh` / `--reset` manage the cache
227
+ (reference.md). `--skip-test` skips the init-time TCP connection test; it is implied
228
+ automatically when `--use-env-refs` is set (the `$env` refs have no value to connect with yet).
229
+ `--system` is optional for v2 — without it the engine is inferred from `--env-file` / `.env`
230
+ (`DATABASE_URL` scheme), defaulting to `postgresql`.
290
231
 
291
232
  ### env-refs (keep secrets out of `.dbcli`)
292
233
 
234
+ Store credentials as `{ "$env": "VAR" }` references resolved at runtime, never plaintext:
235
+
293
236
  ```bash
294
- dbcli init --use-env-refs \
295
- --env-host DB_HOST --env-port DB_PORT \
296
- --env-user DB_USER --env-password DB_PASSWORD --env-database DB_NAME
237
+ # Default key names: DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_DATABASE
238
+ dbcli init --use-env-refs
239
+
240
+ # Non-default key names — name each one explicitly (required in CI):
241
+ dbcli init --conn-name prod --env-file .env.production --use-env-refs --skip-test \
242
+ --env-host PROD_DB_HOST --env-port PROD_DB_PORT \
243
+ --env-user PROD_DB_USER --env-password PROD_DB_PASSWORD --env-database PROD_DB_NAME
297
244
  ```
298
245
 
299
- Stored as `{ "$env": "DB_HOST" }` etc. and resolved at runtime. Pair with
300
- `--env-file <path>` (v2) when each connection has its own env file.
246
+ In an **interactive terminal**, omitting the `--env-*` flags prompts for each key name
247
+ (defaults above) you can type a non-default name like `PROD_DB_PASSWORD` and it is stored
248
+ as a `$env` ref. In a **non-interactive / CI** run you **must** pass all five `--env-*`
249
+ flags; otherwise `init` exits with an error — it never silently falls back to plaintext.
250
+ `--env-file <path>` is the path to the env file, independent of the `$env` key names.
301
251
 
302
252
  ### Common gotchas
303
253
 
@@ -328,7 +278,7 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
328
278
  | `q` | query-only+ | Run a saved snippet by `@name` with `--param k=v`. Supports `--verify` to run assertions. |
329
279
  | `queries` | n/a | Manage saved snippets: `list` / `show` / `search` / `suggest` / `new` / `edit` / `check` / `delete` / `rename` / `copy` / `import` / `export`. |
330
280
  | `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`. |
331
- | `delete` | data-admin+ | SQL or MongoDB only. `--where` required; `--dry-run` first. Supports `--recovery`. |
281
+ | `delete` | data-admin+ | SQL or MongoDB; Redis has a basic implementation (see Redis section). `--where` required; `--dry-run` first. Supports `--recovery`. |
332
282
  | `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. Supports `--recovery`. |
333
283
  | `blacklist` | n/a | `list` / `table` / `column` subcommands redact sensitive data from query results. |
334
284
  | `check` | query-only+ | SQL only (best on MySQL/MariaDB). |
@@ -336,10 +286,10 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
336
286
  | `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`. |
337
287
  | `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>`. |
338
288
  | `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. |
339
- | `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 with suggestedCommands, slowest, errors, hotTables, N+1) — `--format`, `--top`, `--slow-ms`, `--n-plus-one`. |
289
+ | `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`, `--slow-ms` (default `1000`), `--redact none\|literals`. Observe-only. **(v1.27)** `proxy analyze` aggregates the event log offline into a JSON/text report (summary, byFingerprint with suggestedCommands, slowest, errors, hotTables, N+1) — errors out if no events exist yet. |
340
290
  | `status` | query-only+ | Safe JSON/text summary (no credentials). |
341
291
  | `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`. |
342
- | `report` | query-only+ | Diagnostic report (health / capacity / perf) built from `@diag/*` snippets. `--section`, `--brief`, `--for-agent`, `--no-connect`. |
292
+ | `report` | query-only+ | Diagnostic report built from `@diag/*` snippets. `--section <health\|capacity\|perf>` (comma-separated to combine), `--brief`, `--for-agent`, `--no-connect`. |
343
293
  | `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`). |
344
294
  | `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. |
345
295
  | `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. |
@@ -347,11 +297,27 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
347
297
  | `completion` | n/a | bash / zsh / fish scripts. |
348
298
  | `upgrade` | n/a | Self-update from npm; 24h-cached version hints on every command. |
349
299
  | `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). |
350
- | `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 LLM prompt context payload. |
300
+ | `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). |
351
301
  | `migrate` | admin | SQL only. **DDL; dry-run by default** — needs `--execute`. |
352
302
 
353
- `--use <name>` on any subcommand targets a v2 connection without changing the default.
354
- `--recovery` is honoured by `query`, `q`, `insert`, `update`, `delete`, `export`, `schema`, and `inspect`; on failure these emit a `RecoveryEnvelope` JSON to stdout, suppress the human stderr message, and atomically save the envelope to `.dbcli/last-recovery.json` for `dbcli recover` to consume.
303
+ `--use <name>` on any subcommand (including `status` / `doctor`) targets a v2 connection
304
+ without changing the default. `--recovery` is honoured by `query`, `q`, `insert`, `update`,
305
+ `delete`, `export`, `schema`, and `inspect` (see **On failure** above).
306
+
307
+ **Write & query flag semantics** (SQL/Mongo `insert`/`update`):
308
+
309
+ - `--set` (update) / `--data` (insert) take a **JSON object string**, not a SQL fragment:
310
+ `dbcli update users --where "id=42" --set '{"email":"new@example.com"}'`. For MongoDB, a
311
+ JSON without `$` operators is auto-wrapped as `$set`; explicit operators pass through.
312
+ `insert --data` can also read the object from stdin.
313
+ - `--where` (SQL) accepts only `col=val` or `col1=val1 AND col2=val2` — **not** full SQL
314
+ (no `>=`, `!=`, `LIKE`, `OR`). MongoDB `--where` takes a full JSON filter
315
+ (`'{"status":"pending"}'`), falling back to `col=val` when it is not valid JSON.
316
+ - `--dry-run` prints the parameterized SQL (with `$1` / `?` placeholders, not real values)
317
+ and `rows_affected: 0`; proceed once `status:"success"` and the SQL shape matches the
318
+ intended `--where` / `--set`. MongoDB prints a shell-style preview.
319
+ - `--recovery` is recommended for automated agent pipelines (enables `dbcli recover --apply`
320
+ after a failure); optional for one-off manual writes.
355
321
 
356
322
  ## Permission levels
357
323
 
@@ -362,170 +328,116 @@ Full flags and edge cases: see [reference.md](reference.md) `init` section.
362
328
  | data-admin | + DELETE (DML, no DDL) |
363
329
  | admin | + DDL via `migrate` and destructive ops |
364
330
 
365
- ## Multi-connection (v2)
366
-
367
- - Each named connection has its own schema dir: `.dbcli/schemas/<connection>/`.
368
- - Run `dbcli schema --use <name>` once per connection before `schema <table>` — otherwise the cache may return another connection's columns.
369
- - `schema --refresh` / `--reset` manage the cache; see reference.md.
370
-
371
331
  ## MongoDB
372
332
 
373
- - JSON filter object (`find`) or JSON array (`aggregate`); SQL is rejected. `--collection <name>` is required on `query`.
374
- - **Supported:** `init`, `list`, `schema` (sampled), `query`, `insert`, `update`, `delete`, `export`, `q` (saved queries), `status`, `use`, `shell`, `doctor`, `upgrade`, `completion`.
375
- - **Not supported:** `diff`, `migrate`, `check`.
376
- - Schema is **sampled** by `$sample` (default 100 docs, max 1000). Pass `--sample-method natural` to use `find().limit()` instead. Columns surface as dot-paths (e.g. `profile.tokens.access`) with `presence` (0..1) and `redacted: true` flags for blacklist hits.
377
- - **Write planner tiers:** `$set`/`$unset` → `ALLOW`; `$rename` `WARN` (informational); `$inc`/`$mul`/`$min`/`$max`/`$currentDate` `WARN`; `$push`/`$pull`/`$pullAll`/`$pop`/`$addToSet` → `WARN`; `$bit` → `WARN`; `$where` and unknown operators → `BLOCK`.
378
- - **Nested blacklist:** `blacklist.columns[<collection>]` accepts dotted paths (`profile.email`) and trailing-wildcard prefixes (`profile.tokens.*`); middle wildcards are rejected with a warning at `dbcli blacklist list`. Read paths replace matched values with the literal string `[REDACTED]`.
379
- - **Saved queries:** snippet file ends in `.mongodb.sql`. Frontmatter requires `engine: mongodb` and `operation: find` or `operation: aggregate`. `target: <collection>` is the default collection (override with `--collection`). Body is JSON (object for `find`, array for `aggregate`); `{{param}}` placeholders are JSON-encoded.
380
- - See reference.md MongoDB section for full syntax and examples.
333
+ - `query` takes a JSON filter object (`find`) or array (`aggregate`); SQL is rejected.
334
+ `--collection <name>` is required on `query`.
335
+ - **Supported:** `init`, `list`, `schema` (sampled), `query`, `insert`, `update`, `delete`,
336
+ `export`, `q`, `status`, `use`, `shell`, `doctor`. **Not supported:** `diff`, `migrate`, `check`.
337
+ - Schema is **sampled** by `$sample` (default 100 docs, max 1000; `--sample-method natural`
338
+ uses `find().limit()`). Columns surface as dot-paths (e.g. `profile.tokens.access`) with
339
+ `presence` (0..1) and `redacted` flags.
340
+ - Writes: `--set` / `--data` JSON is auto-wrapped as `$set` when no `$` operator is present;
341
+ explicit operators (`$set`/`$inc`/`$push`/…) pass through. Nested blacklist accepts dotted
342
+ paths (`profile.email`) and trailing wildcards (`profile.tokens.*`). Saved snippets end in
343
+ `.mongodb.sql` (frontmatter `engine: mongodb`, `operation: find|aggregate`). Full
344
+ write-planner tiers and syntax: reference.md MongoDB section.
381
345
 
382
346
  ## Redis
383
347
 
384
- - Command-style execution; `query` runs a whitelisted Redis command (e.g. `GET`, `HSET`, `DEL`).
385
- - **Supported:** `init`, `list` (keys via SCAN), `schema <key>` (type / TTL / size / sample), `query`, `shell`, `status`, `use`, `doctor`, `upgrade`, `completion`.
386
- - **Not supported:** `schema` full scan, `insert`, `update`, `delete`, `export`, `check`, `diff`, `migrate`, `q`.
387
- Use `query "DEL <key>"` etc. for writes they go through the same permission gate.
388
- - Permission tiers map to commands: read commands → `query-only`; mutators (`SET`, `HSET`, ...) → `read-write`; `DEL` / `UNLINK` → `data-admin`.
389
- - `database` field is the logical DB index (default `0`); `list` returns ≤ 100 000 keys via SCAN.
390
- - **Size guard:** `SCAN`/`HSCAN`/`SSCAN`/`ZSCAN` inject `COUNT 1000`; `LRANGE`/`ZRANGE` clamp `stop`; `ZRANGEBYSCORE` injects `LIMIT 0 1000`; `HGETALL`/`HKEYS`/`HVALS`/`SMEMBERS`/`KEYS` truncate at 1000. Results carry `warnings[]` (`REDIS_SIZE_REWRITE` / `REDIS_SIZE_TRUNCATE`). Pass `--no-limit` (CLI) or `.no-limit on` (shell) to bypass.
391
- - **Blacklist:** `dbcli blacklist add 'secrets:*'` registers a Redis-native key glob. Reads/writes whose keys match are rejected (`BlacklistRejection`, audited with `metadata.matched_pattern`); `KEYS`/`SCAN MATCH` overlapping a rule are rejected; non-overlapping listings filter blacklisted keys.
392
- - **Masking (v1.22):** add a `redis.mask` block to `.dbcli` — keys matching a `keyPattern` glob have their value (or named hash `fields`) returned as `[REDACTED]` on reads (`GET`, `GETRANGE`, `HGETALL`, `HGET`, `HMGET`, `HVALS`). Masking coexists with key-glob rejection, and **rejection always wins over masking**.
393
- - **Shell:** `dbcli shell` on a Redis connection opens a single-line REPL (history, tab completion of commands + key prefixes, `.no-limit on/off`).
394
- - See reference.md Redis section.
348
+ - `query` runs a single **whitelisted** Redis command (e.g. `GET`, `SET`, `HSET`, `DEL`).
349
+ The full whitelist and the per-command permission tier are defined in reference.md.
350
+ - **Supported:** `init`, `list` (keys via SCAN), `schema <key>` (type / TTL / size / sample),
351
+ `query`, `q` (saved snippets**read-only commands only**), `delete` (basic implementation:
352
+ `DEL` / `HDEL` / `LREM` / `SREM` / `ZREM`, needs `data-admin`; `query "DEL <key>"` also
353
+ works), `shell`, `status`, `use`, `doctor`. **Not supported:** `schema` full scan,
354
+ `insert`, `update`, `check`, `diff`, `migrate`.
355
+ - **Permission tiers:** reads (`GET`/`HGET`/`SCAN`/…) `query-only`; mutators
356
+ (`SET`/`HSET`/`INCR`/`EXPIRE`/`SETEX`/`RENAME`/…) `read-write`; `DEL`/`UNLINK`/`HDEL`/`XDEL`
357
+ `data-admin`. A command not in the whitelist is refused.
358
+ - **No `--dry-run` for Redis `query`** — write safety comes from the permission gate and key
359
+ blacklist (matching reads/writes are rejected). To preview a delete, use `delete <key> --dry-run`.
360
+ - `database` is the logical DB index (default `0`). `dbcli blacklist add 'secrets:*'`
361
+ registers a key glob; an optional `redis.mask` block masks values on read. Size guards
362
+ (SCAN/HGETALL truncation, `--no-limit` to bypass) and masking details: reference.md Redis section.
395
363
 
396
364
  ## Elasticsearch
397
365
 
398
- - DSL (JSON body) or Lucene query string; `--collection <index>` is required on `query`.
399
- - **Supported:** `init`, `list` (indices with doc count), `schema [index]` (flattened mapping), `query`, `export` (v1.22), `shell` (v1.22), `status`, `use`, `doctor`, `upgrade`, `completion`.
400
- - **Not supported:** `insert`, `update`, `delete`, `check`, `diff`, `migrate`, `q`.
401
- Writes are not exposed via dedicated subcommands yet — use `query` if the cluster allows or external tools.
402
- - **Export (v1.22):** `dbcli export` takes a search DSL with `--index <index>` to export hits, or an index name as the query to scroll the whole index via `match_all`. Outputs JSON / JSONL / CSV (default 1000 rows; `--no-limit` scrolls the full index in batches). Index-level blacklist + audit apply.
403
- - **Shell (v1.22):** `dbcli shell` opens a Kibana Dev Tools-style REPL request line `<METHOD> /<path>` plus an optional multi-line JSON body, submitted with a blank line; index-level blacklist rejects protected indices and `_search` auto-caps at 1000 when `size` is omitted.
404
- - Query-only mode caps at 1000 hits; `--no-limit` is bounded at 10 000.
405
- - Schema flattens nested fields (`a.b.c`) and surfaces `.fields` multi-fields.
406
- - See reference.md Elasticsearch section.
366
+ - `query` takes a DSL (JSON body) or Lucene query string; `--collection <index>` is required.
367
+ - **Supported:** `init`, `list` (indices with doc count), `schema [index]` (flattened mapping),
368
+ `query`, `export` (v1.22), `shell` (v1.22), `status`, `use`, `doctor`. **Not supported:**
369
+ `insert`, `update`, `delete`, `check`, `diff`, `migrate`.
370
+ - `export` takes a search DSL with `--index <index>`, or an index name as the query to scroll
371
+ the whole index via `match_all`. Query-only caps at 1000 hits; `--no-limit` is bounded at 10 000.
372
+ - Schema flattens nested fields (`a.b.c`) and surfaces `.fields` multi-fields. `shell` opens a
373
+ Kibana Dev Tools-style REPL. Full syntax and examples: reference.md Elasticsearch section.
407
374
 
408
375
  ## Saved queries
409
376
 
410
- Run reusable parameterised SELECT snippets stored in your repo.
377
+ Run reusable parameterised snippets stored in your repo.
411
378
 
412
379
  | Step | Command |
413
380
  |------|---------|
414
- | 1. Discover | `dbcli queries list` |
381
+ | 1. Discover | `dbcli queries list` (or `queries search <keywords>` / `queries suggest <intent>`) |
415
382
  | 2. Inspect | `dbcli queries show @<name>` |
416
- | 3. Run | `dbcli q @<name> --param k=v` |
417
-
418
- ### When you don't know which query to run
383
+ | 3. Run | `dbcli q @<name> --param k=v` (blacklist always enforced) |
419
384
 
420
- 1. `dbcli queries search <keywords>` — natural keywords, fuzzy ranked
421
- 2. `dbcli queries suggest <intent>` — browse a category
422
- Common intents: perf.slow-query, perf.cache-hit, capacity.size,
423
- safety.connections, monitor.cluster-health
424
- 3. Once you find one: `dbcli q @<name>` (blacklist always enforced)
385
+ Common intents: `perf.slow-query`, `perf.cache-hit`, `capacity.size`, `safety.connections`,
386
+ `monitor.cluster-health`.
425
387
 
426
- Snippets resolve from three layers, **local > shared > builtin** (local wins):
427
- - `builtin` bundled with dbcli (e.g. `@diag/*`); read-only at runtime
428
- - `.dbcli-shared/queries/` committed, team-shared
429
- - `.dbcli/queries/` gitignored, personal override
388
+ Snippets resolve **local > shared > builtin** (local wins): `builtin` (bundled `@diag/*`,
389
+ read-only) / `.dbcli-shared/queries/` (team) / `.dbcli/queries/` (personal). Manage local
390
+ snippets with `queries new | edit | delete | rename | copy | import | export`. Each `.sql`
391
+ file declares YAML frontmatter inside `-- ---` blocks (name, description, engine, params, tags,
392
+ optional `intent`, optional `visual`).
430
393
 
431
- Manage local snippets with `queries new | edit | delete | rename | copy | import | export`
432
- (see reference.md). Use `copy` / `import` to fork a builtin or shared snippet into the
433
- local layer for editing.
434
-
435
- Each `.sql` file may declare YAML frontmatter inside `-- ---` blocks
436
- (name, description, engine, params, tags, optional `intent`, optional `visual`).
437
- The `visual:` block drives the interactive dashboard (see "Interactive HTML dashboard"
438
- below). See `dbcli queries show @<name> --format json` for the machine-readable contract.
439
-
440
- ### Engine-specific bodies
441
-
442
- Each snippet's body format is determined by the `engine` frontmatter field:
394
+ Body format by `engine`:
443
395
 
444
396
  | Engine | Body format | Notes |
445
397
  |-------------------|------------------------|-------|
446
398
  | postgres / mysql | Single SELECT or WITH | `:name` → driver bind (`$1` / `?`) |
447
399
  | elasticsearch | JSON DSL | `:name` → JSON-aware substitution; `index:` field required |
448
- | redis | Single Redis command | `:name` → raw text; only read commands allowed |
400
+ | redis | Single Redis command | `:name` → raw text; **only read commands allowed** |
449
401
 
450
402
  Mixed-family `engine` arrays (e.g. `[postgres, elasticsearch]`) are rejected at parse time.
451
403
 
452
404
  ### Built-in diagnostic snippets
453
405
 
454
- dbcli ships ready-made diagnostic queries. Run with `dbcli q @diag/<topic>`:
406
+ Run with `dbcli q @diag/<topic>` (engine variant auto-picked by the active connection):
455
407
 
456
408
  | key | purpose |
457
409
  |-------------------------|------------------------------------------|
458
410
  | `@diag/connections` | active sessions |
459
- | `@diag/long-running` | queries above `min_seconds` (default 30) |
411
+ | `@diag/long-running` | queries above `min_seconds` (`--param min_seconds=N`, default 30) |
460
412
  | `@diag/table-sizes` | table data/index size with row counts |
461
413
  | `@diag/index-usage` | indexes by scan count |
462
414
  | `@diag/missing-indexes` | tables dominated by sequential scans |
463
415
  | `@diag/locks` | lock-wait chains |
464
416
  | `@diag/db-size` | database size summary |
465
417
  | `@diag/cache-hit` | buffer cache hit ratios |
466
- | `@diag/es-cluster-health` | document counts per index (ES connections) |
467
- | `@diag/redis-key-stats` | sample SCAN over keyspace (Redis connections) |
468
-
469
- Engine variants are picked automatically based on the active connection.
470
- Override any of them by placing a same-named file under `.dbcli-shared/queries/`
471
- or `.dbcli/queries/`.
418
+ | `@diag/es-cluster-health` | document counts per index (ES) |
419
+ | `@diag/redis-key-stats` | sample SCAN over keyspace (Redis) |
472
420
 
473
421
  ## Interactive HTML dashboard
474
422
 
475
- `query`, `q`, and `export` can render results as a standalone, self-contained HTML
476
- report powered by a bundled React + Recharts template (`assets/ui-template.html`,
477
- injected via a hardened `window.__DBCLI_PAYLOAD__ = {...}` block — `<` is escaped
478
- to neutralise `</script>` payloads).
423
+ `query`, `q`, and `export` can render results as a standalone, self-contained HTML report
424
+ (bundled React + Recharts template).
479
425
 
480
426
  ```bash
481
- # Open in browser (writes to a temp file, then `open`/`xdg-open`/`start`)
482
- dbcli query "SELECT day, dau FROM dau_daily" --ui
483
- dbcli q @analytics/revenue --param days=30 --ui
484
-
485
- # Pipe HTML to stdout (CI artifacts, email, static hosting)
486
- dbcli query "SELECT * FROM orders" --format html > orders.html
487
-
488
- # Export to a file (interchangeable with json/jsonl/csv)
427
+ dbcli query "SELECT day, dau FROM dau_daily" --ui # open in browser
428
+ dbcli query "SELECT * FROM orders" --format html > out.html # pipe HTML to stdout
489
429
  dbcli export "SELECT * FROM orders" --format html --output orders.html
490
430
  ```
491
431
 
492
- `--ui` implies `--format html` and opens the file; `--format html` alone prints to
493
- stdout. Blacklist redaction is applied **before** rendering the dashboard never
494
- sees masked columns.
495
-
496
- ### Snippet `visual:` block
497
-
498
- To get KPIs and charts (rather than just a sortable table), add a `visual:` block
499
- to the snippet's frontmatter. Column names must exist in the result row.
500
-
501
- ```sql
502
- -- ---
503
- -- name: Revenue Trend
504
- -- engine: postgres
505
- -- params:
506
- -- days: { type: int, default: 30 }
507
- -- visual:
508
- -- title: Revenue (last :days days)
509
- -- kpis:
510
- -- - { label: Total Revenue, value_column: total_revenue, format: currency }
511
- -- - { label: Orders, value_column: order_count, format: number }
512
- -- - { label: Conversion, value_column: conv_rate, format: percent }
513
- -- charts:
514
- -- - { type: line, title: Daily Revenue, x: day, y: [revenue] }
515
- -- - { type: bar, title: By Channel, x: channel, y: [revenue, refunds] }
516
- -- ---
517
- SELECT ...
518
- ```
519
-
520
- - `kpis[].format`: `currency` / `number` / `percent` (omit for raw value).
521
- - `charts[].type`: `line` / `bar` / `area` / `pie` / `scatter`.
522
- - Raw `query` invocations (no snippet) render a sortable/filterable table only —
523
- there is no `visual:` to attach.
432
+ `--ui` implies `--format html` and opens the file; `--format html` alone prints to stdout.
433
+ Blacklist redaction is applied **before** rendering. To get KPIs and charts instead of a plain
434
+ table, add a `visual:` block (`title`, `kpis[]`, `charts[]`) to the snippet frontmatter — see
435
+ reference.md for the full `visual:` schema. Raw `query` invocations render a sortable table only.
524
436
 
525
437
  ## Common workflows
526
438
 
527
439
  - **Debug odd state:** `schema` → `check` → `query` with tight `WHERE` → follow FKs from schema JSON. Evidence over theory.
528
- - **After INSERT/UPDATE:** `--dry-run` → run → `query` read-back; explain mismatches via triggers, defaults, or blacklist.
440
+ - **After INSERT/UPDATE:** follow the write sequence in **How to use dbcli** (`--dry-run` → run → `query` read-back); explain mismatches via triggers, defaults, or blacklist.
529
441
  - **Migrations:** `diff --snapshot` → `migrate` (dry-run → `--execute`) → `diff --against` → `check` affected tables. DROP requires `--force`.
530
442
  - **Health / growth:** `check --all` (huge tables skipped unless `--include-large`); consult schema `sizeCategory` before ad-hoc queries.
531
443
  - **Codegen from live DB:** `schema --format json` to drive an ORM; cross-check once with `dbcli query`.