rdq

RDS Data API Query — A terminal UI for querying Aurora over the AWS RDS Data API, with built-in Amazon Bedrock assistance.
[!WARNING]
This project is under active development. Features and keybindings may change without notice.
Overview
rdq is a Go-based TUI that wraps the AWS RDS Data API (ExecuteStatement) so you can:
- Edit SQL in a multi-line editor and run it against Aurora over HTTPS (no VPC / bastion required)
- See results as a table or JSON, drill into a single row, export to CSV, or yank to the clipboard
- Generate SQL from natural language with Amazon Bedrock, with multi-turn chat history within a session
- Get automatic, in-context error explanations whenever a query fails
- Switch between AWS profiles, clusters, secrets, Bedrock models, and response languages without leaving the TUI
The gui subcommand exposes a browser-based SQL client (React + Vite SPA embedded in the binary) that delivers the same core experience: SQL execution, result viewing, CSV / JSON export, schema browsing, history, and Bedrock-assisted Ask / Review / Analyze / Explain flows. exec and ask are placeholder stubs and will be wired to the same engines as the TUI in a future release.
Features
TUI mode (default)
- Multi-line SQL editor with execute via
F5 or ^R
- Result viewer with three sub-modes:
- Table view — vim-style cursor:
j / k for rows, h / l / 0 / $ for columns, with horizontal scroll for wide tables and a ▸ marker on the active column
- JSON view (
^J toggle) — viewport with j / k / gg / G and h / l / 0 / $ for horizontal scroll
- Row inspector (
Enter) — preserves long values on a single line; scroll vertically with j / k / gg / G and horizontally with h / l / 0 / $; footer shows line N/M
- Cursor position indicator — table footer always shows
row N/M · col K/L <name> so the user can tell where they are
- vim-style yy yank copies the current view (table CSV / result JSON / row JSON / explanation) to the system clipboard with an auto-clearing flash confirmation (~2.5 s)
- CSV export (
^E) writes the current result to a timestamped file in cwd
- SQL history stored per profile, recallable via the history picker (
^H) with incremental substring filter. Favourites: press ^F inside the picker to mark / unmark an entry; favourites float to the top of the list and survive across runs
AI integration (Amazon Bedrock)
- Ask AI (
^G) — natural-language prompt → SQL replaces the editor contents. Multi-turn chat history is preserved within a session, so follow-ups like "now sort by created_at desc" inherit context. The chat resets when you switch cluster or profile (the previous schema no longer applies). Failed prompts are automatically removed from the history so retries do not duplicate turns
- F6 = unified review / analyze / explain — picks the right action based on focus + screen state:
- Editor focus + non-empty SQL → review the SQL (correctness / performance / safety / style)
- Results focus + result rows → analyze the result (counts, distributions, outliers)
- Results focus + error → explain the error (root cause + fix, with the verbatim DB error always shown above the analysis)
- Background schema fetch —
information_schema is fetched and cached so AI prompts can resolve real table / column names without re-querying
- Per-profile model + language — choose a Bedrock inference profile / foundation model (
^O) and a response language (^L — Japanese / English / Chinese / Korean / Spanish / French) once and they are remembered
Connection management
- AWS profile picker (
^P) — incremental substring search over ~/.aws/config profiles, switch the active credentials without restarting; rebuilds the SDK clients and reloads the cached connection for the new profile
- Cluster picker (
^T) — list Aurora clusters with the Data API enabled in the active region
- Secret picker (
^\) — switch the secret used for the current cluster (read-only ↔ admin etc.) without going through the cluster picker first
- Automatic cluster→secret resolution — when picking a cluster the matching secret is found via, in order:
- Per-profile cluster→secret cache in
~/.rdq/state.json
- The cluster's
MasterUserSecret (RDS-managed password)
- Secrets tagged
aws:rds:primaryDBClusterArn = <cluster ARN>
- Falling back to a region-wide secret picker
- Persistent state — profile / cluster / secret / database / Bedrock model / language are cached so subsequent launches skip the prompts
- Ephemeral mode for direct credentials — when no profile name is in play (
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY only), rdq walks through the cluster / secret / database pickers from scratch every launch and writes nothing to ~/.rdq/state.json or the history log. The status bar shows (direct credentials · ephemeral) so the mode is visible
- Friendly credentials error — if no provider in the SDK chain can produce credentials,
rdq exits with an actionable message instead of the raw SDK error
Safety features (TUI + GUI)
Both modes share the same guards so destructive SQL is hard to run by accident:
- Read-only mode (default on for fresh profiles) — only
SELECT / WITH / SHOW / EXPLAIN / DESCRIBE / DESC / TABLE / VALUES can execute. Everything else is rejected before the request reaches AWS.
- TUI: toggle with
F8; the status bar shows a RO marker when it is on.
- GUI: toggle in Settings; the connection bar shows a Read-only badge (or Allow writes when off).
- Production environment flag — per profile. When set, the GUI connection bar flips to a warning colour and the TUI shows a matching indicator, so destructive statements stand out visually before you run them.
- Destructive-statement confirmation —
DELETE / UPDATE without a WHERE clause, and TRUNCATE, open a confirmation prompt (TUI) or dialog (GUI) with the exact statement. Nothing is sent to AWS until you acknowledge it. The guard understands line / block comments and string literals, so UPDATE t SET col = '-- just a string' is not misclassified as "commented-out WHERE".
Flags are stored per profile in ~/.rdq/state.json and survive restarts.
GUI mode (browser-based SQL client)
Launch with rdq gui (opens http://127.0.0.1:8080 in your browser automatically; add --no-open to suppress). The GUI shares the same internal/ engines as the TUI, so results, history, and schema caches are consistent across both surfaces.
- Connection wizard — pick profile → cluster → secret → database from browser-side searchable lists; the selection persists to
~/.rdq/state.json just like the TUI. Each field also has a one-click switcher in the connection bar (Profile / Cluster / Database badges) so you can rebind without reopening the full wizard.
- CodeMirror 6 SQL editor — syntax highlighting, schema-aware autocomplete,
Cmd/Ctrl+Enter to run. If text is selected, only the selection runs.
- Result viewer with Table / JSON / Info tabs, row detail dialog, CSV / JSON download, and one-click Copy to clipboard (CSV or JSON).
- Find in result —
Cmd/Ctrl+F opens a search bar over the Result Table. Enter / Shift+Enter step to the next / previous match (with a running N / M counter), matches are highlighted in the table, and the active match is accented and scrolled into view. The same substring is also highlighted in the schema sidebar's filter.
- Resizable layout — drag the vertical handle to resize Schema ↔ Editor+Result, and the horizontal handle to resize Editor ↔ Result. Your layout is saved to
localStorage and restored on reload.
- History panel — per-profile SQL log with substring search, favourites toggle, "Load into editor", and per-row Copy. Duplicate statements are de-duplicated on append: running the same SQL twice keeps one entry with the latest timestamp (favourite status is preserved).
- Schema sidebar — filterable table / column tree; double-click to insert qualified names into the editor; click a row to copy the qualified identifier to the clipboard.
- Bedrock AI dialogs — Ask (natural language → SQL with multi-turn chat), Review (critique current SQL), Analyze (interpret last result), Explain (diagnose an error). Each response renders as Markdown with syntax-highlighted code blocks, and adapts to light / dark theme. Explain opens automatically with the last error pre-filled when you click the Explain button.
- Safety badges — the connection bar always shows Read-only or Allow writes and flips to a warning palette when the active profile is flagged as production. See Safety features.
- Security — the server binds
127.0.0.1 only and enforces Origin / Host checks against the localhost allow-list; --dev temporarily adds http://localhost:5173 so cd frontend && npm run dev proxying works during frontend development.
- Graceful shutdown —
SIGINT / SIGTERM drains in-flight requests within 10 s.
Installation
go install github.com/Tocyuki/rdq/cmd/rdq@latest
Or build from source:
git clone https://github.com/Tocyuki/rdq.git
cd rdq
go build -o rdq ./cmd/rdq/
Usage
Quick start
rdq
rdq with no arguments launches the TUI. The first run walks you through profile / cluster / secret / database selection. Subsequent runs jump straight in using the cached connection.
Global flags
| Flag |
Short |
Description |
--profile |
-p |
AWS profile (falls back to AWS_PROFILE). Pass without a value for an interactive picker. |
--cluster |
|
Aurora cluster ARN. Pass without a value for an interactive picker. |
--secret |
|
Secrets Manager secret ARN. Pass without a value for an interactive picker. |
--database |
|
Database name. Pass without a value to pick from history or enter manually. |
--bedrock-model |
|
Override the cached Bedrock model ID (env: RDQ_BEDROCK_MODEL). |
--bedrock-language |
|
Override the cached response language (env: RDQ_BEDROCK_LANGUAGE). |
--debug |
-d |
Verbose logging. |
GUI subcommand flags
Only applies to rdq gui. The TUI uses neither flag.
| Flag |
Short |
Default |
Description |
--port |
-P |
8080 |
Port the embedded HTTP server listens on. |
--no-open |
|
false |
Skip opening the browser automatically on launch. |
TUI keybindings
Global
| Key |
Action |
F5 / ^R |
Execute SQL |
Tab |
Move focus between editor and results pane |
^J |
Toggle table / JSON view |
Enter |
Open row inspector (in table view) / close inspector |
^G |
Ask AI — open natural-language prompt input (always SQL generation) |
F6 |
Review / analyze / explain — picks the right one from current focus + state |
^P |
Switch AWS profile |
^T |
Switch cluster |
^\ |
Switch secret for the current cluster |
^O |
Switch Bedrock model |
^L |
Switch Bedrock response language |
^H |
SQL history picker (substring filter; ^F toggles favourite on selected entry) |
^E |
Export the current result to CSV in the working directory |
F8 |
Toggle read-only mode (shows a RO marker in the status bar while on) |
Esc |
Clear error / close current overlay |
? |
Toggle full help |
^C |
Quit |
Table view (results focus)
| Key |
Action |
j / ↓ |
Next row |
k / ↑ |
Previous row |
l / → |
Next column (with horizontal scroll for wide tables) |
h / ← |
Previous column |
0 / Home |
Jump to first column |
$ / End |
Jump to last column |
Enter |
Open row inspector |
yy |
Yank entire result as CSV |
Row inspector (after Enter)
| Key |
Action |
j / k / ↓ / ↑ |
Scroll one line |
gg / G |
Jump to top / bottom |
h / l / ← / → |
Horizontal scroll (4 cells) |
0 / $ / Home / End |
Jump to left / right edge |
yy |
Yank current row JSON |
Enter / Esc |
Close inspector |
Long values stay on a single line, so use h / l / 0 / $ to scroll across wide JSON values — the same navigation as the JSON view.
JSON view (^J) and explanation overlay (after F6 on an error)
| Key |
Action |
j / k |
Scroll one line |
gg / G |
Jump to top / bottom |
h / l |
Horizontal scroll (4 cells) |
0 / $ |
Left edge / right edge |
yy |
Yank current view |
Esc |
Close overlay |
All pickers (profile / cluster / secret / model / language / history) support type-to-filter incremental search with substring matching. Selection happens with Enter; Esc cancels. Inside the history picker, ^F marks/unmarks an entry as a favourite (★).
AI workflow examples
Generate SQL from natural language:
- Press
^G from the editor → enter a natural-language prompt → Enter
- The generated SQL replaces the editor contents (the previous draft is preserved in
^H history if you ran it)
- Review and press
F5 to execute
- Press
^G again to refine: "now group by month and sort desc" — the model sees the previous turn
Review the SQL you just wrote:
- With the editor focused and a SQL statement on screen, press
F6
- An optional focus area prompt appears — type something like
performance or index usage to narrow the review, or press Enter with an empty prompt for a general review
- The model returns a markdown review (correctness / performance / safety / style) inside the result pane
Analyze a query result:
- Run a query that returns rows
- Press
Tab to focus the results pane
- Press
F6 → an optional focus area prompt appears (same as review); press Enter with an empty prompt for a general summary, or type something like outliers to narrow the analysis
- The model summarises counts, distributions, outliers and surfaces notable patterns
Explain an error:
- Run a SQL statement that fails — the error is shown in the results pane
- Press
Tab to focus results, then F6
- The model returns
## Database error (verbatim DB error) + ## Analysis (root cause + suggested fix)
Cluster ↔ Secret matching
If your cluster uses RDS-managed master passwords (MasterUserSecret), the matching secret is selected automatically. If your secrets are managed by Terraform / IaC and the picker still asks every time, simply select the right secret once and rdq will remember the pairing in ~/.rdq/state.json for next time.
Direct credentials (ephemeral mode)
When you start rdq without a profile name in play (no --profile, no AWS_PROFILE, but AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY are exported), the TUI runs in ephemeral mode:
- Status bar shows
(direct credentials · ephemeral)
- Cluster / secret / database pickers run from scratch every launch
- Nothing is written to
~/.rdq/state.json or the SQL history file
- Switching to a named profile from inside the TUI (
^P) re-enables persistence
State files
| Path |
Purpose |
~/.rdq/state.json |
Per-profile cache: cluster ARN, secret ARN, database, Bedrock model, response language, cluster→secret map, database history, plus the isReadOnly / isProduction safety flags |
~/.rdq/history.jsonl |
SQL execution history (append-only JSONL); each entry stores its profile + database so the picker can filter |
~/.rdq/schema/<hash>.json |
Cached information_schema snapshot per (cluster, database) pair |
Override locations with RDQ_STATE_FILE, RDQ_HISTORY_FILE, RDQ_SCHEMA_DIR if needed.
In ephemeral mode (direct credentials, no profile name) none of these files are touched.
AWS Profile resolution
rdq picks the active profile through the following branches:
| Invocation |
Result |
rdq -p value |
Use value |
rdq -p (no value) + AWS_PROFILE=foo |
Use foo (skip the picker — env wins) |
rdq -p (no value), env unset |
Open the interactive fuzzy picker |
rdq (no flag) + AWS_PROFILE=foo |
Use foo |
rdq (no flag) + AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY (no AWS_PROFILE) |
Use the SDK default credentials chain → ephemeral mode |
rdq (no flag), nothing configured |
Friendly error message + exit 1 |
Inside the TUI, ^P opens the profile picker again at any time. Switching to a named profile from ephemeral mode re-enables persistence and history.
Prerequisites
- AWS credentials configured (
~/.aws/credentials, SSO, env vars, ...)
- IAM permissions:
- RDS —
rds:DescribeDBClusters
- Secrets Manager —
secretsmanager:GetSecretValue, secretsmanager:ListSecrets, secretsmanager:DescribeSecret
- RDS Data API —
rds-data:ExecuteStatement
- Bedrock (optional, only for AI features) —
bedrock:Converse, bedrock:ListInferenceProfiles, bedrock:ListFoundationModels
- An Aurora cluster with the Data API enabled
Tech stack
Implementation status
| Feature |
Status |
rdq (TUI default) |
✅ Implemented |
rdq tui |
✅ Implemented |
rdq gui |
✅ Implemented (separate React SPA, browser-based) |
rdq exec <sql> (one-shot CLI) |
🚧 Stub |
rdq ask <prompt> (one-shot CLI) |
🚧 Stub |
| Vim mode editor |
🚧 Planned |
Visual selection / dd / p |
🚧 Planned |
Development
git clone https://github.com/Tocyuki/rdq.git
cd rdq
make hooks # one-time: install the pre-commit gofmt guard
make go-build # Go-only build
./rdq --help
make fmt # gofmt -w .
make check # fmt-check + vet + test -race (mirrors CI)
make check is the exact set of steps the CI "Go" job runs, so a
green make check locally means a green CI. The make hooks target
installs a tiny pre-commit hook (.githooks/pre-commit) that runs
gofmt -l on any staged Go files — it catches the most common "red
CI" mistake before the commit lands without slowing down
git commit with test runs.
For the GUI mode (browser SPA), make build runs the Vite frontend build and embeds it into the Go binary. See CLAUDE.md for the layered architecture overview.
License
This project is licensed under the MIT License. See LICENSE for details.