# dbcli — Database CLI for AI Agents **Languages:** [English](./README.md) | [繁體中文](./README.zh-TW.md) A unified database CLI tool that enables AI agents (Claude Code, Gemini, Copilot, Cursor) to safely query, discover, and operate on databases. **Core Value:** AI agents can safely and intelligently access project databases through a single, permission-controlled CLI tool with sensitive data protection. > **Security update:** `dbcli init` now writes only a small project binding stub into `./.dbcli/config.json`. The full connection configuration is stored under `~/.config/dbcli/projects//config.json`, so sensitive settings do not live inside the project workspace by default. ## Internationalization (i18n) dbcli supports multiple languages via the `DBCLI_LANG` environment variable: ```bash # English (default) dbcli init # Traditional Chinese DBCLI_LANG=zh-TW dbcli init # Or set in .env export DBCLI_LANG=zh-TW dbcli init ``` **Supported languages:** - `en` — English (default) - `zh-TW` — Traditional Chinese (Taiwan) All messages, help text, error messages, and command output respond to the language setting automatically. ## Quick Start ### Installation #### Global Installation (Recommended) ```bash npm install -g @carllee1983/dbcli # or: bun install -g @carllee1983/dbcli ``` #### Zero-Install (No Installation Needed) ```bash npx @carllee1983/dbcli init npx @carllee1983/dbcli query "SELECT * FROM users" # or with Bun: bunx @carllee1983/dbcli init ``` #### Update ```bash # Self-update (recommended) dbcli upgrade # Or via npm npm update -g @carllee1983/dbcli ``` #### Development Installation ```bash git clone https://github.com/CarlLee1983/dbcli.git cd dbcli bun install bun run src/cli.ts -- --help # or: bun run dev -- --help ``` When `dbcli` is not on your `PATH`, use `bun run src/cli.ts ...` (same as `bun run dev -- ...`). ### First Steps ```bash # Initialize project with database connection dbcli init # Interactive shell (SQL + dbcli commands, tab completion) dbcli shell # List available tables dbcli list # View table structure dbcli schema users # Query data dbcli query "SELECT * FROM users" # Preview schema DDL (dry-run by default; add --execute to apply) dbcli migrate create posts --column "id:serial:pk" --column "title:varchar(200):not-null" # Generate AI agent skill dbcli skill --install claude ``` ### Agent first-look ```bash dbcli inspect --for-agent ``` A single read-only command that returns a bounded JSON snapshot of the current connection, permission level, blacklist size, schema cache freshness, available saved-query intents, and the safest next commands to run. No host, no port, no credentials — safe to log or pipe to an LLM. ### Diagnostic report ```bash dbcli report --format json ``` Builds on `inspect` to also run curated read-only built-in `@diag/*` snippets grouped into `health` / `capacity` / `perf` sections. Bounded by per-snippet timeout and per-evidence row cap. Use `--format markdown` for human reading, `--section health,capacity` to scope, or `--for-agent` for compact JSON. ### Guide ```bash dbcli guide slow-query --format json ``` Deterministic next-command planner. Pick a goal (`slow-query`, `capacity`, `health`, `index-usage`, `permissions`, `schema-overview`) and `dbcli guide` emits an ordered plan that combines `dbcli inspect`, engine-appropriate `@diag/*` snippets, and `dbcli queries suggest` / `dbcli doctor` follow-ups. The planner is cache-first (no network); add `--probe` to refresh the underlying inspect context. Use `--list` to see all goals, `--format markdown` for human reading, or `--for-agent` for compact JSON. ### Interactive HTML Dashboards ```bash # Open results in browser dbcli query "SELECT * FROM orders" --ui # Run a saved snippet with visualization metadata dbcli q @analytics/revenue --ui # Export query results as a standalone HTML file dbcli export "SELECT * FROM users" --format html --output report.html ``` `dbcli` can render query results as fully interactive, standalone HTML dashboards. These reports are powered by React + Recharts and are zero-dependency — the entire application and data are inlined into a single HTML file. - **`--ui` flag**: Automatically generates a temporary report and opens it in your default browser. - **`visual:` block**: Snippet frontmatter can define KPIs and charts (Line, Bar, Area, Pie, Scatter) to drive the dashboard. - **Security**: Result sets are redacted by the blacklist before injection, and data is safely escaped for HTML. ### Recovery & Guided Remediation ```bash # Lookup recovery commands for a code dbcli recovery --code CONN_REFUSED --format json # Execute a failing command with recovery opt-in dbcli query "SELECT 1" --recovery # (v1.17.0+) Inspect or apply the last saved recovery plan dbcli recover # View last plan (Markdown) dbcli recover --apply # Execute safe steps (readonly/dry-run) dbcli recover --apply --allow-write=readonly-cmd # Allow local writes dbcli recover --apply --allow-write=write-cmd # Allow database writes # (v1.17.0+) Multi-turn recovery (for AI agents) dbcli recover --next --after-step 1 --result '{"status":"ok"}' ``` Machine-readable error envelope with guided remediation. As of v1.16.0 every first-party command accepts the `--recovery` flag. In v1.17.0, the `recover` command was added to automate the execution of these plans. - **Risk Gating:** `--apply` is safe-by-default, running only `readonly` and `dry-run` steps. Elevated tiers require `--allow-write`. - **Verification:** After a successful `--apply`, dbcli automatically runs a verification step to confirm the fix actually worked. - **Multi-turn Protocol:** The `--next` flag allows agents to advance recovery one step at a time, providing the result of the previous step to enable deterministic branching. `dbcli inspect --require-schema-cache` throws `SCHEMA_CACHE_MISSING` when the active SQL connection has no usable schema cache; combine with `--recovery` to receive the structured envelope. For write commands (`insert` / `update` / `delete`), `BLACKLIST_COLUMN_WRITE` and `PERMISSION_DENIED` envelopes lead with a `risk: 'dry-run'` step that suggests previewing the SQL with `--dry-run` before re-attempting. ### MongoDB Atlas / SRV Connections MongoDB connections are supported via both standard `mongodb://` URIs and Atlas-style `mongodb+srv://` URIs. ```bash # Atlas / SRV connection dbcli init --system mongodb --conn-name atlas --uri "mongodb+srv://user:pass@cluster.example.mongodb.net/mydb" # List collections in the configured MongoDB database dbcli list --use atlas # Query a collection with JSON filter or pipeline dbcli query '{"status":"active"}' --collection users --use atlas ``` For MongoDB, `list` and `query` operate on the database configured for the connection, and `query` requires `--collection `. For a command-by-command support matrix across PostgreSQL, MySQL, MariaDB, MongoDB, Redis, and Elasticsearch, see [docs/feature-matrix.md](./docs/feature-matrix.md). ### Redis & Elasticsearch Support dbcli extends its unified interface to Redis and Elasticsearch, providing consistent discovery and querying. #### Redis ```bash # Connect to Redis dbcli init --system redis --host localhost --port 6379 # List keys (uses SCAN) dbcli list # Inspect a key (type, TTL, size, sample) dbcli schema my-key # Run Redis commands (whitelisted) dbcli query "GET my-key" dbcli query "HGETALL user:1" ``` #### Elasticsearch ```bash # Connect to Elasticsearch dbcli init --system elasticsearch --host localhost --port 9200 # List indices and document counts dbcli list # Show mapping/structure of an index dbcli schema my-index # Query using Lucene or DSL JSON dbcli query "status:active" --index my-index dbcli query '{"query": {"match_all": {}}}' --index my-index ``` --- ## Multi-connection Support (v2) dbcli supports multiple named database connections within a single project. This is useful for managing different environments (development, staging, production) or multiple databases. The project `.dbcli` directory now acts as a binding + cache layer. The actual connection config is stored in `~/.config/dbcli/projects//`, which keeps sensitive settings out of the workspace by default. ### Initializing Named Connections To create a named connection, use the `--conn-name` option during `init`. You can also specify a custom `.env` file for that connection. ```bash # Add a staging connection using .env.staging dbcli init --conn-name staging --env-file .env.staging # Add a production connection with environment variable references dbcli init --conn-name prod --env-file .env.production --use-env-refs ``` ### Managing Connections Use the `dbcli use` command to switch between connections or list them. ```bash # List all connections (* marks the current default) dbcli use --list # Switch the default connection to 'staging' dbcli use staging # Show the current default connection dbcli use # Remove a connection dbcli init --remove staging # Rename a connection dbcli init --rename staging:production ``` ### Using a Specific Connection Temporarily You can use the `--use ` global flag to execute any command against a specific connection without changing the default. ```bash # Query the production database once dbcli query "SELECT count(*) FROM users" --use prod # Check staging table health dbcli check users --use staging ``` --- #### `dbcli init` Initialize a new dbcli project with database connection configuration. **Usage:** ```bash dbcli init [OPTIONS] ``` **Options (Basic):** - `--system ` — Database system: `postgresql`, `mysql`, `mariadb`, `mongodb` - `--host ` — Database host - `--port ` — Database port - `--user ` — Database user - `--password ` — Database password - `--name ` — Database name - `--permission ` — Permission level: `query-only`, `read-write`, `data-admin`, `admin` - **MongoDB only:** `--uri ` — full connection URI (`mongodb://…` or `mongodb+srv://…`); `--auth-source ` — auth database (default `admin` when using user/password) - `--use-env-refs` — Store environment variable references instead of actual values in config - `--skip-test` — Skip connection test - `--no-interactive` — Non-interactive mode (requires all options) - `--force` — Overwrite existing config without confirmation **Options (Multi-connection v2):** - `--conn-name ` — Create a named connection (e.g., `staging`, `prod`) - `--env-file ` — Load credentials from a specific `.env` file for this connection - `--remove ` — Remove a named connection from the config - `--rename ` — Rename an existing connection (format: `old:new`) **Behavior:** - Reads `.env` file if present (auto-fills DATABASE_URL, DB_* variables) - Prompts for missing values (host, port, user, password, database name, permission level) - Creates a project binding stub in `.dbcli/config.json` and stores the full config under `~/.config/dbcli/projects//` - Tests database connection before saving **Examples:** ```bash # Interactive initialization dbcli init # Multi-connection setup dbcli init --conn-name staging --env-file .env.staging dbcli init --conn-name prod --env-file .env.production --use-env-refs # Store env var references (non-interactive) dbcli init --use-env-refs --system mysql \ --env-host DB_HOST --env-port DB_PORT \ --env-user DB_USER --env-password DB_PASSWORD \ --env-database DB_DATABASE \ --no-interactive ``` --- #### `dbcli use` (Requires v2 config) Manage or switch the default database connection in multi-connection projects. **Usage:** ```bash dbcli use [connection-name] [OPTIONS] ``` **Options:** - `--list` — List all connections and show the current default **Examples:** ```bash # Show current default connection dbcli use # Switch default connection to 'prod' dbcli use prod # List all connections dbcli use --list ``` --- > **`--use-env-refs`:** When enabled, the config stores environment variable names (e.g., `{"$env": "DB_HOST"}`) instead of actual values. This avoids writing sensitive credentials into the config file, making it suitable for multi-environment deployments and CI/CD pipelines. At connection time, dbcli automatically reads the actual values from the referenced environment variables. > **Storage model:** The project `.dbcli` directory is now a binding + cache layer, not the canonical home for secrets. If you inspect `./.dbcli/config.json`, you should only see the binding metadata; the full config lives in the home storage path shown above. --- #### `dbcli list` List all tables in the connected database. **Usage:** ```bash dbcli list [OPTIONS] ``` **Options:** - `--format json` — Output as JSON instead of ASCII table **Examples:** ```bash # Table format (human-readable) dbcli list # JSON format (for AI parsing) dbcli list --format json # Pipe to tools dbcli list --format json | jq '.data[].name' ``` --- #### `dbcli schema [table]` Show table structure (columns, types, constraints, foreign keys). **Usage:** ```bash dbcli schema [table] dbcli schema # Scan entire database and update .dbcli dbcli schema users # Show structure of 'users' table ``` **Options:** - `--format json` — Output as JSON - `--refresh` — Detect and update schema changes incrementally (requires --force for approval) - `--reset` — Clear all existing schema data and re-fetch from database (useful after switching DB connections) - `--force` — Skip confirmation for schema refresh/overwrite/reset **Examples:** ```bash # Show users table structure dbcli schema users # JSON output with full metadata dbcli schema users --format json # Update schema with new tables (incremental) dbcli schema --refresh --force # Clear and re-fetch all schema (after switching DB) dbcli schema --reset --force # Scan entire database dbcli schema ``` --- #### `dbcli query "SQL"` Execute SQL query and return results. **Usage:** ```bash dbcli query "SELECT * FROM users" ``` **Options:** - `--format json|table|csv` — Output format (default: table) - `--limit ` — Cap rows (overrides the automatic limit in query-only mode) - `--no-limit` — Disable the automatic 1000-row cap in query-only mode **Behavior:** - Enforces permission-based restrictions (Query-only mode blocks INSERT/UPDATE/DELETE) - Auto-limits results to 1000 rows in Query-only mode (notification shown), unless `--no-limit` or `--limit` applies - Returns structured results with metadata (row count, execution time) - To write CSV/JSON to a file, use shell redirection or the `export` command **Examples:** ```bash # Table output (human-readable) dbcli query "SELECT * FROM users" # JSON (for AI/programmatic parsing) dbcli query "SELECT * FROM users" --format json # CSV to stdout (redirect to a file) dbcli query "SELECT * FROM users" --format csv > users.csv # Pipe to other tools dbcli query "SELECT * FROM products" --format json | jq '.data[] | .name' # Large result sets (paginate with LIMIT/OFFSET) dbcli query "SELECT * FROM users LIMIT 100 OFFSET 0" ``` --- #### `dbcli insert [table]` (Requires Read-Write or Admin permission) Insert data into table. **Usage:** ```bash dbcli insert users --data '{"name": "Alice", "email": "alice@example.com"}' ``` **Options:** - `--data JSON` — Row data as JSON object (REQUIRED) - `--dry-run` — Show SQL without executing - `--force` — Skip confirmation **Behavior:** - Validates JSON format - Generates parameterized SQL (prevents SQL injection) - Shows confirmation prompt before inserting (unless --force used) **Examples:** ```bash # Insert single row dbcli insert users --data '{"name": "Bob", "email": "bob@example.com"}' # Preview SQL without executing dbcli insert users --data '{"name": "Charlie"}' --dry-run # Skip confirmation dbcli insert users --data '{"name": "Diana"}' --force ``` --- #### `dbcli update [table]` (Requires Read-Write or Admin permission) Update existing rows. **Usage:** ```bash dbcli update users --where "id=1" --set '{"name": "Alice Updated"}' ``` **Options:** - `--where condition` — WHERE clause (REQUIRED, e.g., "id=1 AND status='active'") - `--set JSON` — Updated columns as JSON object (REQUIRED) - `--dry-run` — Show SQL without executing - `--force` — Skip confirmation **Examples:** ```bash # Update single row dbcli update users --where "id=1" --set '{"name": "Alice"}' # Update multiple rows dbcli update users --where "status='inactive'" --set '{"status":"active"}' # Preview SQL dbcli update users --where "id=1" --set '{"name": "Bob"}' --dry-run # Skip confirmation dbcli update users --where "id=2" --set '{"email": "new@example.com"}' --force ``` --- #### `dbcli delete [table]` (Requires Data-Admin or Admin permission) Delete rows (blocked for query-only and read-write; requires elevated DML permission). **Usage:** ```bash dbcli delete users --where "id=1" --force ``` **Options:** - `--where condition` — WHERE clause (REQUIRED) - `--dry-run` — Show SQL without executing - `--force` — Required to actually delete (safety guard) **Examples:** ```bash # Delete single row (requires --force) dbcli delete users --where "id=1" --force # Preview deletion dbcli delete products --where "status='deprecated'" --dry-run # Delete multiple rows dbcli delete orders --where "created_at < '2020-01-01'" --force ``` --- #### `dbcli export "SQL"` Export query results to file. **Usage:** ```bash dbcli export "SELECT * FROM users" --format json --output users.json ``` **Options:** - `--format json|csv` — Output format - `--output file` — Write to file (default: stdout for piping) **Behavior:** - Query-only permission limited to 1000 rows per export - Generates RFC 4180 compliant CSV - Creates well-formed JSON arrays **Examples:** ```bash # Export to JSON dbcli export "SELECT * FROM users" --format json --output users.json # Export to CSV dbcli export "SELECT * FROM orders" --format csv --output orders.csv # Pipe compressed export dbcli export "SELECT * FROM products" --format csv | gzip > products.csv.gz # Combine with query tools dbcli export "SELECT * FROM users WHERE active=true" --format json | jq '.data | length' ``` --- #### `dbcli skill` Generate or install AI agent skill documentation. **Usage:** ```bash dbcli skill # Output skill to stdout dbcli skill --output SKILL.md # Write to file dbcli skill --install claude # Install to Claude Code config dbcli skill --install gemini # Install to Gemini CLI (being phased out) dbcli skill --install antigravity # Install to Antigravity CLI (Gemini CLI's successor) dbcli skill --install copilot # Install to GitHub Copilot dbcli skill --install cursor # Install to Cursor IDE dbcli skill --install codex # Install to Codex skills dbcli skill --install windsurf # Install to Windsurf (.windsurfrules) ``` **Behavior:** - Ships canonical **`assets/SKILL.md`** + **`assets/reference.md`** (single source of truth: concise skill + long command reference) - Prints the skill to **stdout**, writes it with **`--output`**, or copies it to a **platform-specific path** with **`--install`** - Actual database access is still enforced by your `.dbcli` permission level and blacklist — the skill text describes the full CLI surface **Examples:** ```bash # Generate skill for Claude Code dbcli skill --install claude # Generate skill manually for documentation dbcli skill > ./docs/SKILL.md # View generated skill (stdout) dbcli skill # Install for all platforms dbcli skill --install claude && \ dbcli skill --install gemini && \ dbcli skill --install antigravity && \ dbcli skill --install copilot && \ dbcli skill --install cursor && \ dbcli skill --install codex ``` --- #### `dbcli blacklist` Manage the data access blacklist to block AI agents from accessing sensitive tables or columns. **Usage:** ```bash dbcli blacklist list dbcli blacklist table add dbcli blacklist table remove
dbcli blacklist column add
. dbcli blacklist column remove
. ``` **Subcommands:** | Subcommand | Description | |------------|-------------| | `dbcli blacklist list` | Show current blacklist (tables and columns) | | `dbcli blacklist table add
` | Add table to blacklist (blocks all operations) | | `dbcli blacklist table remove
` | Remove table from blacklist | | `dbcli blacklist column add
.` | Add column to blacklist (omitted from SELECT results) | | `dbcli blacklist column remove
.` | Remove column from blacklist | **Behavior:** - Table blacklist blocks all operations on that table (query, insert, update, delete) - Column blacklist silently omits columns from SELECT results and shows a security notification - Blacklist rules are stored in `.dbcli` and apply to all permission levels - Override for admin use via `DBCLI_OVERRIDE_BLACKLIST=true` environment variable **Examples:** ```bash # View current blacklist dbcli blacklist list # Block all access to sensitive tables dbcli blacklist table add audit_logs dbcli blacklist table add secrets_vault # Hide sensitive columns from query results dbcli blacklist column add users.password_hash dbcli blacklist column add users.ssn # Remove a table from blacklist dbcli blacklist table remove audit_logs # Remove a column from blacklist dbcli blacklist column remove users.ssn # Override blacklist (admin use only) DBCLI_OVERRIDE_BLACKLIST=true dbcli query "SELECT * FROM secrets_vault" ``` --- #### `dbcli check` Run data-quality and health checks on tables. **Usage:** ```bash dbcli check [table] [OPTIONS] ``` **Options:** - `--all` — Check every table (skips huge tables unless `--include-large`) - `--include-large` — Include huge tables in `--all` scan - `--checks ` — Comma-separated checks: `nulls`, `duplicates`, `orphans`, `emptyStrings`, `rowCount`, `size` - `--sample ` — Sample size for large tables (default: 10000) - `--format json|table` — Output format (default: json) **Examples:** ```bash # Check users table dbcli check users # Run specific checks only dbcli check orders --checks nulls,orphans --format table # Scan all tables dbcli check --all # Table view + all-tables with selected checks dbcli check orders --format table dbcli check --all --checks nulls,duplicates --format json ``` --- #### `dbcli diff` Save a schema snapshot or compare the live database to a previous snapshot (tables, columns, indexes). **Usage:** ```bash dbcli diff --snapshot ./schema-before.json dbcli diff --against ./schema-before.json dbcli diff --against ./schema-before.json --format table ``` **Options:** - `--snapshot ` — Write the current schema to a JSON file - `--against ` — Diff live schema vs. the saved snapshot - `--format json|table` — Output format (default: `json`) - `--config ` — Config path (default: `.dbcli`) --- #### `dbcli snapshot` Capture a **result fingerprint** of a query (distinct from `diff`, which snapshots *schema*): row count plus per-column aggregates (null/distinct counts, min/max/sum) and an order-independent checksum. Blacklisted columns are masked at the source, so the snapshot is safe to store. Use it as a baseline for `dbcli assert --against`. SQL engines only. **Usage:** ```bash dbcli snapshot "SELECT * FROM orders WHERE created_at >= '2026-05-01'" # → .dbcli/snapshots/snap-.json dbcli snapshot @analytics/daily-revenue --out base.json dbcli snapshot "SELECT status, count(*) FROM orders GROUP BY status" --stdout ``` **Options:** - `--out ` — Output path (default: `.dbcli/snapshots/snap-.json`) - `--rows` — Also store the full (blacklist-masked) rows - `--stdout` — Print snapshot JSON to stdout instead of writing a file - `--format json|table` — Output format for `--stdout` (default: `json`) - `--no-limit` — Disable the automatic query-only LIMIT --- #### `dbcli assert` Assert an **invariant** on a query result. Exits `1` on failure (composes in scripts/CI) unless `--no-fail`. SQL engines only. **Usage:** ```bash dbcli assert "SELECT count(*) FROM orders" --expect "value > 0" dbcli assert "SELECT * FROM orders WHERE total < 0" --expect "rows == 0" dbcli assert "SELECT email FROM users" --expect "col:email not null" dbcli assert "SELECT sum(amount) FROM ledger_a" --vs "SELECT sum(amount) FROM ledger_b" --compare value dbcli assert "SELECT * FROM orders" --against base.json --tolerance 0.01 ``` **Options:** - `--expect ` — `rows > 0`, `value == 5000`, `col:email not null`, `col:id unique`, `col:amount between 0 and 100`, `col:age >= 18` - `--vs ` — Reconcile against a second query - `--compare rows|value` — Comparison mode for `--vs` (default: `value`) - `--against ` — Compare the current result fingerprint to a saved snapshot - `--tolerance ` — Allowed relative drift for `--against` (e.g. `0.01`; default: `0` = exact checksum match) - `--no-fail` — Always exit 0; report pass/fail in output only - `--format json|table` — Output format (default: `json`) --- #### `dbcli proxy` (v1.26) Local-development **observability proxy** for MySQL, MariaDB, and PostgreSQL. Point an existing app at the proxy port; dbcli relays all TCP frames to the real database and appends one JSONL event per query to `.dbcli/proxy/events.jsonl`. Observe-only — no rewrite or blocking. Not a production gateway. **Subcommands:** `mysql` · `mariadb` · `postgresql` ```bash dbcli proxy mysql --listen 127.0.0.1:3307 --target 127.0.0.1:3306 dbcli proxy postgresql --listen 127.0.0.1:5434 --target 127.0.0.1:5432 dbcli proxy mysql --slow-ms 500 --redact literals dbcli proxy mariadb --events ./logs/proxy.jsonl ``` **Options:** - `--listen ` — Proxy listen address - `--target ` — Real database address (inferred from config / `--use` if omitted) - `--events ` — JSONL event log (default: `.dbcli/proxy/events.jsonl`) - `--slow-ms ` — Flag events slower than this threshold as `slow: true` (default: `1000`) - `--redact none|literals` — Strip SQL literal values from event records (default: `none`) - `--format text|json` — Startup output format (default: `text`) --- #### `dbcli status` Show non-sensitive configuration summary (permission level, DB system, blacklist counts, config metadata version). Does not print connection credentials — intended for AI agents. **Usage:** ```bash dbcli status dbcli status --format text dbcli status --format json ``` **Options:** - `--format text|json` — Output format (default: `json`) **Note:** This command reads the default project config path `.dbcli` (not the global `--config` flag). --- #### `dbcli doctor` Run diagnostic checks on environment, configuration, connection, and data. ```bash dbcli doctor # Colored text output dbcli doctor --format json # JSON output for AI agents ``` **Checks:** - **Environment:** Bun version compatibility, dbcli version (compares with npm registry) - **Configuration:** Config file exists/valid, permission level, blacklist completeness - **Connection & Data:** Database connectivity, schema cache freshness (> 7 days warning), large table warnings (> 1M rows) - **MongoDB SRV diagnostics:** For `mongodb+srv://` connections, `doctor` reports whether the current execution environment can resolve SRV records directly or only through the DNS-over-HTTPS fallback used by `dbcli` **Options:** `--format ` **Exit code:** 0 = all pass or warnings only, 1 = errors found --- #### `dbcli completion [shell]` Generate shell completion scripts for tab auto-complete. ```bash dbcli completion bash # Output bash completion to stdout dbcli completion zsh # Output zsh completion to stdout dbcli completion fish # Output fish completion to stdout dbcli completion --install # Auto-detect shell and install to rc file dbcli completion --install zsh # Install for specific shell ``` **Supported shells:** bash, zsh, fish Installed completions cover **nested subcommands** — for example `dbcli queries list --`, `dbcli migrate add-column --`, and `dbcli verify safe-backfill --`. Inside `dbcli shell`, command completion follows the current command surface, so newly added commands (`q`, `queries`, `inspect`, `verify`, `proxy`, `snapshot`, …) complete and dispatch automatically. `--install` is **marker-managed**: it writes a single block to your shell rc file and re-running it replaces that block rather than duplicating it. --- #### `dbcli upgrade` Check for updates and self-upgrade dbcli. ```bash dbcli upgrade # Check and upgrade if newer version available dbcli upgrade --check # Only check, do not upgrade ``` **Options:** `--check` — check only, don't install **Background checks (stderr, skipped when `--quiet` or for `upgrade` / `skill`):** - **CLI version:** dbcli checks the npm registry (cached, about once per 24 hours). If a newer package exists, a one-line hint prints after normal command output. - **Installed skills:** If you used `dbcli skill --install `, dbcli compares each installed primary skill file (`SKILL.md` or `dbcli.mdc`) to the bundled `assets/SKILL.md`. When they differ, a short reminder lists which platforms to re-install (`dbcli skill --install `). Run `dbcli upgrade` to see the same skill status together with version info. Re-installing also refreshes `reference.md` next to the skill. #### `dbcli shell` Interactive database shell with SQL execution, auto-completion, and syntax highlighting. **Usage:** ```bash dbcli shell # Interactive mode (SQL + dbcli commands) dbcli shell --sql # SQL-only mode ``` **Inside the shell:** - Type SQL statements ending with `;` to execute queries - Type dbcli commands without the `dbcli` prefix (e.g., `schema users`, `list`) - Press Tab for context-aware auto-completion (SQL keywords, table/column names) - Use `.help` for meta commands (`.quit`, `.clear`, `.format`, `.history`, `.timing`) - Multi-line SQL: input accumulates until `;` is found - History persists across sessions in `~/.dbcli_history` **Permission:** Inherits from config. SQL and commands are fully permission/blacklist enforced. #### `dbcli migrate` Schema DDL operations. **All commands default to dry-run** — use `--execute` to actually run the SQL. **Usage:** ```bash # Create table dbcli migrate create posts \ --column "id:serial:pk" \ --column "title:varchar(200):not-null" \ --column "body:text" \ --column "created_at:timestamp:default=now()" # Execute (actually run the SQL) dbcli migrate create posts --column "id:serial:pk" --execute # Drop table (destructive — requires --execute --force) dbcli migrate drop posts --execute --force # Column operations dbcli migrate add-column users bio text --nullable --execute dbcli migrate alter-column users name --type "varchar(200)" --execute dbcli migrate alter-column users email --rename user_email --execute dbcli migrate drop-column users temp_field --execute --force # Index operations dbcli migrate add-index users --columns email --unique --execute dbcli migrate drop-index idx_users_email --table users --execute --force # Constraint operations dbcli migrate add-constraint orders --fk user_id --references users.id --on-delete cascade --execute dbcli migrate add-constraint users --unique email --execute dbcli migrate add-constraint users --check "age >= 0" --execute dbcli migrate drop-constraint orders fk_orders_user_id --execute --force # Enum (PostgreSQL only) dbcli migrate add-enum status active inactive suspended --execute dbcli migrate alter-enum status --add-value archived --execute dbcli migrate drop-enum status --execute --force ``` **Column spec format:** `name:type[:modifier...]` — Modifiers: `pk`, `not-null`, `unique`, `auto-increment`, `default=`, `references=
.` **Options (all subcommands):** `--execute` (run SQL), `--force` (skip confirmation for DROP), `--config ` **Permission:** admin only --- ## Query Risk Planning Use `plan` to inspect SQL safety before execution. It reads local dbcli config, permissions, blacklist rules, and cached schema metadata only; it does not connect to the database. ```bash dbcli plan "UPDATE users SET status='inactive'" --format json ``` Decisions are: - `ALLOW` — no obvious risk was detected. - `WARN` — inspect warnings before executing. - `BLOCK` — unsafe, unsupported, or violates configured safety constraints. Text output is concise for humans: ```text Decision: BLOCK Operation: UPDATE Target tables: users Risk factors: - UPDATE statement has no WHERE clause. Recommendations: - Add a WHERE clause. - Use --dry-run on the actual write command. ``` JSON output includes `suggestedCommands` for agents: ```bash dbcli plan "SELECT id FROM users WHERE id = 1 LIMIT 1" --format json ``` --- ## Global Options All commands support these global options: | Flag | Description | |------|-------------| | `--config ` | Path to .dbcli config file (default: `.dbcli`) | | `--use ` | Use a named v2 connection for this invocation only (does not change the default) | | `-v, --verbose` | Increase verbosity (`-v` verbose, `-vv` debug) | | `-q, --quiet` | Suppress non-essential output | | `--no-color` | Disable colored output (respects `NO_COLOR` env var) | --- ## Internals & Strategy ### Schema Update Strategy dbcli maintains a schema snapshot in your `.dbcli` config file. This allows AI agents to understand the database structure without constant network overhead. Understanding when this cache updates is key: 1. **Manual Updates:** * `dbcli schema`: Performs a full scan of the database. * `dbcli schema --refresh`: Incremental update. Detects changes and updates only the affected tables. * `dbcli schema --reset`: Clears the cache and re-fetches everything. 2. **Automatic Updates (DDL):** * When you execute DDL through `dbcli migrate` (e.g., `add-column`), the CLI automatically re-scans the affected table and updates the `.dbcli` snapshot after successful execution. 3. **Real-time Validation (Non-cached):** * Commands like `insert`, `update`, `delete`, and `check` fetch the latest schema from the database immediately before execution to ensure data integrity, but they **do not** update the long-term snapshot in `.dbcli`. > **Note:** If you change the database schema using external tools (like DBeaver or migration scripts), you **must** run `dbcli schema --refresh` to sync the snapshot so AI agents can see the changes. ### How `dbcli migrate` Works The `migrate` command follows a strict safety pipeline to prevent accidental database corruption: 1. **Permission Check:** Verifies the user has `admin` privileges. DDL is blocked for all other levels. 2. **Blacklist Check:** Ensures the operation isn't targeting a table restricted in the security blacklist. 3. **Dialect-Specific Generation:** The `DDLGenerator` translates your request into the correct SQL for your system: * **PostgreSQL:** Uses `SERIAL`, native `ENUM` types, and double-quoted identifiers. * **MySQL/MariaDB:** Uses `AUTO_INCREMENT`, inline `ENUM` definitions, and backticked identifiers. 4. **Dry-run (Default):** All commands output the generated SQL for review without executing it. 5. **Execution & Confirmation:** * Requires the `--execute` flag to run. * Destructive operations (like `drop`) require both `--execute` and `--force`. 6. **Snapshot Sync:** After successful execution, it automatically triggers a schema refresh for the modified table to keep your `.dbcli` file up to date. --- ## Permission Model dbcli implements a coarse-grained permission system with three levels. Permission level is set during `dbcli init` and stored in `.dbcli` config file. The blacklist system works alongside permissions to provide fine-grained protection for sensitive tables and columns (see [Data Access Control](#data-access-control)). ### Permission Levels | Level | Allowed Commands | Blocked Commands | Use Case | |-------|------------------|------------------|----------| | **Query-only** | `init`, `list`, `schema`, `query`, `export` (limited to 1000 rows) | `insert`, `update`, `delete`, `migrate` | Read-only AI agents, data analysts, reporting | | **Read-Write** | + `insert`, `update` | `delete`, `migrate` | Application developers, content managers | | **Data-Admin** | + `delete` | `migrate` | Full DML access, no DDL | | **Admin** | All commands including `migrate` (DDL) | — | Database administrators, schema modifications | ### Configuration Permission level is set during initialization: ```bash dbcli init # Prompts: permission level (query-only / read-write / data-admin / admin) # Stored in project .dbcli/config.json as: "permission": "query-only" ``` ### Permission-Based Examples #### Query-Only Mode (AI Agent) ```bash # Allowed: Read operations dbcli query "SELECT * FROM users" dbcli schema users dbcli export "SELECT * FROM orders" --format json # Blocked: Write operations dbcli insert users --data '{...}' # ERROR: Permission denied dbcli delete users --where "id=1" # ERROR: Permission denied ``` #### Read-Write Mode (Application Developer) ```bash # Allowed: Read + write dbcli query "SELECT * FROM users" dbcli insert users --data '{"name": "Alice"}' dbcli update users --where "id=1" --set '{"name": "Bob"}' # Blocked: Delete (requires data-admin or admin) dbcli delete users --where "id=1" # ERROR: Permission denied (read-write cannot DELETE) ``` #### Admin Mode (Database Administrator) ```bash # Allowed: Everything including DDL dbcli query "SELECT * FROM users" dbcli insert users --data '{"name": "Eve"}' dbcli update users --where "id=1" --set '{"status": "active"}' dbcli delete users --where "id=1" --force # Data-Admin+ can delete dbcli migrate create posts --column "id:serial:pk" --execute # Admin only ``` ### Best Practices - **AI Agents:** Use Query-only for read-only scenarios; prevents accidental data loss - **Applications:** Use Read-Write for normal CRUD operations; prevents DROP TABLE accidents - **Maintenance:** Use Admin only for schema changes, bulk deletes, or emergency operations - **Principle of Least Privilege:** Assign minimum permission level needed for each use case --- ## Data Access Control dbcli provides a blacklist system that works alongside the permission model to prevent AI agents from accessing sensitive tables or columns, regardless of their permission level. ### Table-Level Blacklist Blocking a table prevents all operations on it — queries, inserts, updates, and deletes are all refused with a clear error message. ```bash # Block a table dbcli blacklist table add secrets_vault # Attempting access is blocked at all permission levels dbcli query "SELECT * FROM secrets_vault" # ERROR: Table 'secrets_vault' is blacklisted ``` ### Column-Level Blacklist Blacklisted columns are silently omitted from SELECT results. A security notification is shown in the output so the agent is aware that the result set has been filtered. ```bash # Blacklist sensitive columns dbcli blacklist column add users.password_hash dbcli blacklist column add users.ssn # Query returns all other columns; notification shown dbcli query "SELECT * FROM users" # [Security] Columns omitted by blacklist: password_hash, ssn ``` ### Security Notifications Whenever a blacklist rule filters query output, dbcli appends a notification line to the result. This ensures AI agents do not silently operate on incomplete data without awareness. ### Override via Environment Variable Administrators can bypass the blacklist for emergency or maintenance operations using the `DBCLI_OVERRIDE_BLACKLIST=true` environment variable: ```bash DBCLI_OVERRIDE_BLACKLIST=true dbcli query "SELECT * FROM secrets_vault" ``` This override is logged and should only be used by administrators when necessary. ### Blacklist Configuration Blacklist rules are stored in the `.dbcli` config file and can also be set manually: ```json { "blacklist": { "tables": ["audit_logs", "secrets_vault"], "columns": { "users": ["password_hash", "ssn"] } } } ``` ### Blacklist vs. Permissions The blacklist and permission model are complementary layers of access control: | Layer | Controls | Applies To | |-------|----------|------------| | **Permission Model** | Operation type (read/write/delete) | All tables | | **Blacklist** | Specific tables and columns | Targeted sensitive data | A Query-only agent cannot write to any table, and also cannot read blacklisted tables or columns — both restrictions apply simultaneously. --- ## Saved queries Save parameterised SELECT snippets and re-run them by name: ```bash dbcli queries list dbcli queries show @dau dbcli q @dau --param days=30 --format json ``` Snippets live in `.dbcli-shared/queries/` (committed) or `.dbcli/queries/` (gitignored, personal override). Each `.sql` file declares its frontmatter in a `-- ---` block. Read `assets/reference.md` for the full schema. --- ## AI Integration Guide dbcli ships AI-consumable skill files (`assets/SKILL.md` and `assets/reference.md`) and can copy them into your favorite AI tool directories. ### Quick Start Generate skill for your preferred platform: ```bash # Claude Code (Anthropic's VS Code extension) dbcli skill --install claude # Gemini CLI (Google's command-line AI) dbcli skill --install gemini # GitHub Copilot CLI dbcli skill --install copilot # GitHub Copilot CLI plugin marketplace # copilot plugin marketplace add CarlLee1983/dbcli # copilot plugin install dbcli-agent@dbcli-agent # Cursor IDE (AI-native editor) dbcli skill --install cursor # Cursor plugin marketplace # /add-plugin dbcli-agent # Codex plugin marketplace # codex plugin marketplace add CarlLee1983/dbcli # Then open /plugins and install dbcli-agent. # Full install guide: plugins/dbcli-agent/INSTALL.md ``` After installation, the AI agent will have access to dbcli commands and can use them to query, insert, update, or export data based on your permission level. ### Platform-Specific Setup #### Claude Code (Anthropic) 1. Install dbcli globally: `npm install -g @carllee1983/dbcli` 2. Initialize: `dbcli init` (choose permission level) 3. Install skill: `dbcli skill --install claude` 4. Restart Claude Code extension 5. In Claude Code chat, ask: "Show me the database schema" or "Query active users" **Skill location:** `~/.claude/skills/dbcli/` (SKILL.md + reference.md) --- #### Gemini CLI (Google) 1. Install dbcli globally: `npm install -g @carllee1983/dbcli` 2. Initialize: `dbcli init` 3. Install skill: `dbcli skill --install gemini` 4. Start Gemini: `gemini start` 5. In chat, request: "Query the users table" or "Show database tables" **Skill location:** `~/.gemini/skills/dbcli/` (SKILL.md + reference.md) --- #### GitHub Copilot CLI 1. Install dbcli globally: `npm install -g @carllee1983/dbcli` 2. Initialize: `dbcli init` 3. Install skill: `dbcli skill --install copilot` 4. Install Copilot CLI: `npm install -g @github-next/github-copilot-cli` 5. Use copilot preview: `copilot --help` and explore dbcli integration **Skill location:** `.github/skills/dbcli/` (SKILL.md + reference.md) when you run `dbcli skill --install copilot` in your project root. --- #### Cursor IDE 1. Install dbcli globally: `npm install -g @carllee1983/dbcli` 2. Initialize: `dbcli init` 3. Install skill: `dbcli skill --install cursor` 4. Open Cursor editor 5. Use Cursor's Composer: "Insert a new user" or "Export user data" **Skill location:** `.cursor/rules/dbcli.mdc` (summary + workflows) and `.cursor/skills/dbcli/reference.md` (full command flags and examples) under the **current working directory** when you run `dbcli skill --install cursor`. **Cursor plugin install:** in Cursor Agent chat, run `/add-plugin dbcli-agent`, or see `plugins/dbcli-agent/INSTALL.md#cursor` for marketplace and fallback options. --- #### Codex 1. Add the marketplace: `codex plugin marketplace add CarlLee1983/dbcli`. 2. Open `/plugins`, select the dbcli Agent marketplace, and install `dbcli-agent`. 3. For a persistent CLI, install dbcli globally: `bun install -g @carllee1983/dbcli` or `npm install -g @carllee1983/dbcli`. 4. Without a global install, the plugin skill uses `bunx @carllee1983/dbcli ` as its fallback. 5. Initialize: `dbcli init` or `bunx @carllee1983/dbcli init`. **Plugin skill location:** `skills/dbcli/` (SKILL.md + reference.md). **Install guide:** `plugins/dbcli-agent/INSTALL.md`. --- ### Example: AI Agent Workflow **Scenario:** You want an AI agent to analyze user engagement data. ```bash # 1. Install and initialize npm install -g @carllee1983/dbcli dbcli init # Choose "query-only" for safety # 2. Install skill to Claude Code dbcli skill --install claude # 3. In Claude Code chat, ask: # "Analyze the last 7 days of user activity and summarize insights" # Claude Code will: # - Use: dbcli schema users, dbcli query "SELECT ..." # - Parse JSON output # - Provide analysis ``` ### Updating the skill after upgrades `dbcli skill` copies the bundled **`assets/SKILL.md`** (and for `--install`, **`assets/reference.md`** next to it). It is **not** regenerated from your live config. When you **upgrade dbcli** or the bundled skill changes, re-copy it to each platform you use: ```bash dbcli skill --install claude dbcli skill --install gemini # ... etc. ``` If an installed primary skill file is older than the bundled `assets/SKILL.md`, dbcli prints a **stderr reminder** after most commands (see **`dbcli upgrade`**). Changing **permission level** or **blacklist** in `.dbcli` affects what the CLI allows at runtime — keep project context (e.g. `dbcli status`, `dbcli blacklist list`) in mind for agents even though the skill text lists the full command set. --- ## Audit Log > **Default ON since v1.20.0.** Existing projects will begin creating > `.dbcli/audit/.jsonl` on first command after upgrading. > Set `audit.enabled = false` in `.dbcli` to opt out. Every command that touches a database writes a structured JSONL entry to `.dbcli/audit/.jsonl`. Inspect the recent history with: ```bash dbcli audit tail --n 10 # last 10 entries on current connection dbcli audit tail --all --for-agent # cross-connection JSON envelope dbcli audit show # full entry by id prefix (>=4 chars) dbcli audit show --recovery-ref # find entry that emitted a recovery envelope dbcli audit health # writer state, rotation %, last write status dbcli audit clear # erase audit log for current connection (prompts y/N) ``` Entries are **metadata-only** — never raw SQL bodies, never `--param` values, never result cell contents. Redaction comes from the same source as v1.19.1's agent-facing JSON contracts (`tests/helpers/sensitive-output.ts`). **Recovery envelope linkage.** When a `--recovery` failure writes `.dbcli/last-recovery.json`, the audit entry's `recovery_ref` field and the envelope's `audit_ref` field reference each other. Agents can pivot between audit history and recovery envelopes from either direction. The `inspect` / `guide` / `recover` / `recover --apply` JSON output embeds `audit_recent: AuditEntryBrief[]` (last 5 entries) so a fresh session has immediate context. **Full bi-directional coverage (v1.20.1+):** Recovery ↔ audit linkage is wired on every `--recovery`-capable command — `query`, `inspect`, `insert`, `update`, `delete`, `export`, `q`, and `schema`. The audit entry's `recovery_ref` and the envelope's `audit_ref` carry matching UUIDs on every failure path, so agents can pivot from a saved envelope (`.dbcli/last-recovery.json`) to its audit entry via `dbcli audit tail --recovery-ref ` (and back via `dbcli audit show --recovery-ref `). The v1.20.0 partial-coverage gap on the 6 DML/DDL commands was closed in v1.20.1. The coverage matrix lives in [`.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md`](./.planning/phases/25-recovery-envelope-bi-directional-linkage/25-J1-COVERAGE-MATRIX.md). For deeper agent workflows (session handoff, forensics walk-through), see [`assets/SKILL.md`](./assets/SKILL.md) §Audit Log usage. --- ## Troubleshooting ### Connection Issues #### "ECONNREFUSED: Connection refused" Database is not running or host/port is incorrect. **Solutions:** ```bash # Verify database is running psql --version # PostgreSQL installed? mysql --version # MySQL installed? # Check connection string dbcli init # Re-run initialization to verify credentials # Verify host/port from command line psql -h localhost -U postgres # PostgreSQL test mysql -h 127.0.0.1 -u root # MySQL test ``` #### "ENOTFOUND: getaddrinfo ENOTFOUND hostname" Hostname resolution failed (typo or DNS issue). **Solutions:** ```bash # Verify hostname in project config (directory layout: .dbcli/config.json) grep host .dbcli/config.json # Test DNS resolution ping your-hostname.com # Use 127.0.0.1 instead of localhost if issues persist dbcli init # Re-initialize with correct host ``` --- ### Permission Errors #### "Permission denied: INSERT requires Read-Write or Admin" Trying to write with Query-only permission level. **Solution:** Re-initialize with higher permission level: ```bash rm -rf .dbcli # Remove project config (destructive — backup if needed) dbcli init # Re-run, choose "read-write", "data-admin", or "admin" ``` #### "Permission denied: DELETE operation requires Data-Admin or Admin" DELETE is not allowed in query-only or read-write mode. **Solution:** Use `data-admin` or `admin` permission (re-run `dbcli init`, or edit `.dbcli/config.json`), or ask an administrator. ```bash dbcli init # Choose "data-admin" or "admin" dbcli delete users --where "id=1" --force ``` --- ### Query Errors #### "Table not found: users" Table doesn't exist or name is misspelled. **Solution:** ```bash # Show all available tables dbcli list # Check spelling and retry dbcli query "SELECT * FROM user" --format json ``` #### "Syntax error near SELECT" SQL syntax error in query. **Solution:** ```bash # Test query in native database client first psql # Or mysql # SELECT * FROM users; <- Test here first # Then use in dbcli dbcli query "SELECT * FROM users" ``` --- ### Performance Issues #### "Query returns 1000 rows instead of full result set" Query-only permission auto-limits results for safety. **Solution:** Increase permission level or fetch data in chunks: ```bash # Re-initialize with higher permission dbcli init # Choose "read-write" or "admin" # OR fetch data in chunks dbcli query "SELECT * FROM users LIMIT 100 OFFSET 0" dbcli query "SELECT * FROM users LIMIT 100 OFFSET 100" ``` #### "CLI startup takes 30+ seconds (first run)" npx is downloading and caching package. **Solution:** This is normal on first run. Subsequent runs are instant: ```bash npx @carllee1983/dbcli init # First run: 30s (downloads) npx @carllee1983/dbcli init # Second run: <1s (cached) # Or install globally for faster startup npm install -g @carllee1983/dbcli dbcli init # All future runs: <1s ``` --- ### Cross-Platform Issues #### Windows: "Command not found: dbcli" npm .cmd wrapper not created or PATH not updated. **Solutions:** ```bash # Restart terminal to refresh PATH # OR reinstall globally npm uninstall -g @carllee1983/dbcli npm install -g @carllee1983/dbcli # Verify installation where dbcli # Windows command to find executable ``` #### macOS/Linux: "Permission denied: ./dist/cli.mjs" Executable bit not set. **Solution:** ```bash chmod +x dist/cli.mjs ./dist/cli.mjs --help ``` --- ## System Requirements ### Database Support - **PostgreSQL:** 12.0+ - **MySQL:** 8.0+ - **MariaDB:** 10.5+ - **MongoDB:** 4.4+ (query and collection listing via `mongodb://` and `mongodb+srv://`; see **MongoDB Atlas / SRV Connections** earlier in this document) ### Runtime - **Node.js:** 18.0.0+ - **Bun:** 1.3.3+ ### Platforms - **macOS:** Intel and Apple Silicon - **Linux:** x86_64 (Ubuntu, Debian, CentOS, etc.) - **Windows:** 10+ (via npm .cmd wrapper) --- ## Development ```bash bun test # full test suite (Bun test runner) bun run typecheck # TypeScript compile-time validation bun run test:unit # unit + core tests only bun run test:integration # integration tests bun run test:docker # integration tests with docker-compose.test.yml (MySQL + PostgreSQL) bun run build # bundle CLI to dist/ (used before publish) ``` CI treats `bun run typecheck` and `bun test` as the required pass/fail validation gate on every push and pull request. Lint, build, smoke checks, and benchmarks run in addition to that gate. Live database integration tests use `.dbcli/config.json` by default. If your live config lives elsewhere, set `LIVE_DB_CONFIG_PATH=/path/to/.dbcli` before running: ```bash LIVE_DB_CONFIG_PATH=/path/to/.dbcli bun test tests/integration/live-db.test.ts ``` If no live config is available, `tests/integration/live-db.test.ts` skips instead of falling back to the default PostgreSQL configuration. Set `SKIP_INTEGRATION_TESTS=true` to skip all integration tests. See [CONTRIBUTING.md](./CONTRIBUTING.md) for full setup, testing, and release process. --- ## License See LICENSE file for details.