pgsavvy

command module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

pgsavvy

CI

A vim-style TUI PostgreSQL client built like lazygit — fast keyboard navigation, modal panes, and a focused workflow for browsing and querying your database from the terminal. The name is short for "PostgreSQL savvy".

pgsavvy demo

Status

Active development. PostgreSQL is the only supported driver so far; breaking changes may occur.

Features

  • PostgreSQL connectivity (pgx) with connection profiles, optional SSH tunnels, and credential strategies: OS keyring, ~/.pgpass, password command, or interactive TUI prompt.
  • Schema browsing — left-rail navigation across schemas, tables, columns, and indexes, with per-rail search (/, n/N), refresh, hidden-schema toggles, and a table-inspect modal (columns, constraints, FKs, indexes).
  • Vim-like SQL editor — modal editing (Normal/Insert/Visual/Visual-Block/Operator-Pending) with motions, operators, text objects (including is/as for SQL statements), registers, undo/redo, . repeat, counts, syntax highlighting (chroma), formatting (sqlfmt), and SQL omni-completion (<c-x><c-o> or auto-trigger) sourced from schema objects, functions, and history.
  • Query execution — run statement-at-cursor or all statements, EXPLAIN / EXPLAIN ANALYZE with an interactive plan tree and plan-doctor insights, write/DDL confirmation gates (including writable-CTE detection), per-statement timeouts, cancellation, and transaction control.
  • Result grids — multiple result tabs (pin/close/cycle), streamed rows with pagination and read-to-end, in-grid search and sort, hide-columns overlay, grid ↔ expanded record view, cell/row yank to clipboard, and export to CSV/TSV/JSON (clipboard or file).
  • Inline cell editing — edit cells by value or SQL expression, stage pending edits per table, review in a commit dialog with optimistic-concurrency conflict resolution and typed-name confirmation for writes.
  • Query history — SQLite-backed persistent history with a recall popup.
  • Discoverability — auto-generated cheatsheet (?), which-key popup for <leader> chords, fully customizable keybindings via YAML config.
  • Theming & i18n — configurable colors (named/hex, truecolor-capable) and locale-aware translations with English fallback.
  • Session logs — per-session structured JSON logs with secret redaction and automatic retention.

In action

SQL omni-completion — auto-triggered table/column suggestions sourced from schema objects, functions, and history (<c-n>/<c-p> to navigate, <c-y> to accept):

pgsavvy omni-completion

Foreign-key navigation — open the relationship panel (<leader>gr) to see a row's parents and children, then follow a foreign key into the referenced row with gd (and <c-o> to jump back):

pgsavvy foreign-key navigation

Install

Prebuilt binaries are published on the Releases page. Each asset is the raw pgsavvy binary for one OS/arch (named pgsavvy_<tag>_<os>_<arch>, .exe on Windows) alongside a checksums.txt. Download the binary for your platform, make it executable, and put it on your PATH:

# example for linux/amd64; adjust the asset name for your platform
curl -fsSLo pgsavvy https://github.com/davesavic/pgsavvy/releases/latest/download/pgsavvy_<tag>_linux_amd64
chmod +x pgsavvy
mv pgsavvy ~/.local/bin/   # or anywhere on your PATH

A release binary is the recommended install because it can update itself in place with pgsavvy update (see Updating below). go install and source builds carry no release metadata and cannot self-update.

go install
go install github.com/davesavic/pgsavvy@latest

Note: go install builds carry no embedded version metadata, so pgsavvy --version reports a placeholder and pgsavvy update refuses to self-update. Install a release binary if you want in-place updates.

Build from source
git clone https://github.com/davesavic/pgsavvy.git
cd pgsavvy
task build       # produces bin/pgsavvy with -ldflags-injected version metadata

See the install & usage guide for full details.

Updating

A release binary updates itself in place:

pgsavvy update

This downloads the matching asset from the latest GitHub Release, verifies its SHA256 against checksums.txt, and atomically replaces the running executable. Re-run pgsavvy afterwards to use the new version.

  • Already on the latest release? It prints an up-to-date message and exits.
  • Builds without release metadata (go install, dev/source builds) refuse to self-update — install a release binary instead.
  • Package-manager / read-only installs (Homebrew, Nix) refuse and defer to that manager.

See docs/INSTALL.md for the full update reference.

Quick Start

pgsavvy          # starts the TUI and opens the connection manager

On first run, create a connection profile in the connection manager (or edit ~/.config/pgsavvy/connections.yml directly), then connect. Press ? for the keybinding cheatsheet; see docs/keybindings.md for the full reference.

Configuration

XDG Base Directory layout:

File Location Purpose
config.yml ~/.config/pgsavvy/ Keybindings, theme, UI/query settings
connections.yml ~/.config/pgsavvy/ Connection profiles
state.yml ~/.local/state/pgsavvy/ App state (last connection, view modes, …)
Session logs ~/.local/state/pgsavvy/sessions/ Per-session JSON debug logs (redacted)

Useful environment variables: PGSAVVY_LOG_DIR (override log directory), PGSAVVY_DISABLE_SESSION_LOG=1 (stderr-only logging), standard XDG_* overrides. See docs/INSTALL.md for the full list.

Requirements

  • Go 1.26
  • go-task v3 — go install github.com/go-task/task/v3/cmd/task@latest
  • golangci-lint v2 — go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
  • Docker Compose — optional, only needed for the Postgres / SSH-tunnel integration fixtures

Development

task --list            # all available tasks
task build             # compile to bin/pgsavvy
task test              # unit tests (forwards args: task test -- -run TestX)
task lint              # golangci-lint v2
task fmt               # gofumpt + goimports via golangci-lint formatters
task vulncheck         # pinned govulncheck

task pg:up             # bring up the Postgres integration fixture
task test:integration  # integration tests (requires PGSAVVY_TEST_PG + fixture)
task test:all          # unit + integration
task pg:down           # tear down the fixture (removes container + volume)

task sshtunnel:up      # SSH bastion + private Postgres fixture (tunnel tests)
task sshtunnel:down

Integration tests are gated by PGSAVVY_TEST_PG; internal/pgprobe fail-loud checks reachability before the suite runs so it can't silently skip. See CONTRIBUTING.md for the full contributor workflow.

Integration fixture gotcha

Bringing the Postgres fixture up against a pre-existing pgdata volume skips the env-driven init step — the official postgres image only honors POSTGRES_USER / POSTGRES_DB on an empty data directory. Before running integration tests against a fresh schema, tear the stack down with the volume:

task pg:down && task pg:up

Documentation

License

Apache 2.0 — Copyright (c) 2026 Dave Savic.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
pgprobe command
Command pgprobe is a fail-loud reachability check used by `task test:integration`.
Command pgprobe is a fail-loud reachability check used by `task test:integration`.
pkg
app
Package app wires application lifecycle and dependency setup.
Package app wires application lifecycle and dependency setup.
cheatsheet
Package cheatsheet ...
Package cheatsheet ...
common
Package common provides the cross-cutting dependency bag (Log, Tr, UserConfig, AppState, Fs) embedded into virtually every receiver downstream.
Package common provides the cross-cutting dependency bag (Log, Tr, UserConfig, AppState, Fs) embedded into virtually every receiver downstream.
config
Package config defines the user-facing configuration schema for pgsavvy (UserConfig, ThemeConfig, KeybindingConfig) and the loaders that read it from YAML files via an afero.Fs.
Package config defines the user-facing configuration schema for pgsavvy (UserConfig, ThemeConfig, KeybindingConfig) and the loaders that read it from YAML files via an afero.Fs.
constants
Package constants ...
Package constants ...
drivers
Package drivers defines the storage-engine-independent driver contract (Driver, Connection, Session, RowStream, Transaction) along with the Capabilities shape, the Factory registry, and the shared error sentinels consumed by every concrete driver under pkg/drivers/*.
Package drivers defines the storage-engine-independent driver contract (Driver, Connection, Session, RowStream, Transaction) along with the Capabilities shape, the Factory registry, and the shared error sentinels consumed by every concrete driver under pkg/drivers/*.
drivers/pg
Package pg implements the Postgres concrete driver: pg.New returns a drivers.Factory that yields a *Driver wrapping a session.Prompter, and *Connection wraps a pgxpool.Pool with ServerVersion caching plus a pg_cancel_backend stub that will be wired in epic E6.
Package pg implements the Postgres concrete driver: pg.New returns a drivers.Factory that yields a *Driver wrapping a session.Prompter, and *Connection wraps a pgxpool.Pool with ServerVersion caching plus a pg_cancel_backend stub that will be wired in epic E6.
env
Package env ...
Package env ...
gui
Package gui hosts the pgsavvy TUI's focus-stack manager and (in later epics) the bootstrap that wires gocui to the Contexts declared in pkg/gui/context.
Package gui hosts the pgsavvy TUI's focus-stack manager and (in later epics) the bootstrap that wires gocui to the Contexts declared in pkg/gui/context.
gui/clipboard
Package clipboard provides the shared clipboard seam used by the vim editor and the results grid + exporter.
Package clipboard provides the shared clipboard seam used by the vim editor and the results grid + exporter.
gui/commands
Package commands defines the CommandRegistry: the named-action table that the keybinding system dispatches into.
Package commands defines the CommandRegistry: the named-action table that the keybinding system dispatches into.
gui/context
Package context contains the concrete Context implementations the pgsavvy TUI focus stack manages: the five side-rail contexts (Connections, Schemas, Tables, Columns, Indexes), the four popup contexts (Menu, Confirmation, Prompt, Suggestions), the command-log EXTRAS context, the GLOBAL context (no view), the LIMIT terminal-too-small overlay, and six StubContext placeholders for Contexts that ship in later epics (QUERY_EDITOR, TABLE_DATA_EDITOR, RESULT_GRID, PLAN, WHICH_KEY, HISTORY).
Package context contains the concrete Context implementations the pgsavvy TUI focus stack manages: the five side-rail contexts (Connections, Schemas, Tables, Columns, Indexes), the four popup contexts (Menu, Confirmation, Prompt, Suggestions), the command-log EXTRAS context, the GLOBAL context (no view), the LIMIT terminal-too-small overlay, and six StubContext placeholders for Contexts that ship in later epics (QUERY_EDITOR, TABLE_DATA_EDITOR, RESULT_GRID, PLAN, WHICH_KEY, HISTORY).
gui/controllers
Package controllers wires keyboard bindings to context state.
Package controllers wires keyboard bindings to context state.
gui/controllers/helpers
Package helpers ...
Package helpers ...
gui/controllers/helpers/data
Package data hosts data-access helpers that adapt drivers.Session into the shape the gui controllers consume.
Package data hosts data-access helpers that adapt drivers.Session into the shape the gui controllers consume.
gui/controllers/helpers/ui
Package ui hosts UI-presentation helpers consumed by the gui controllers: confirm/prompt/toast popups, the table double-click stub, the first-run tip dismissal, and the boxlayout-driven window arrangement.
Package ui hosts UI-presentation helpers consumed by the gui controllers: confirm/prompt/toast popups, the table double-click stub, the first-run tip dismissal, and the boxlayout-driven window arrangement.
gui/editor
Package editor hosts the canonical *Buffer + UndoTree state for one QUERY_EDITOR pane and the per-context gocui.Editor implementations pgsavvy ships outside the COMMAND_LINE master editor.
Package editor hosts the canonical *Buffer + UndoTree state for one QUERY_EDITOR pane and the per-context gocui.Editor implementations pgsavvy ships outside the COMMAND_LINE master editor.
gui/editor/format
Package format provides SQL formatting via sqlfmt.
Package format provides SQL formatting via sqlfmt.
gui/editor/highlight
Package highlight wraps the Chroma v2 PostgreSQL lexer to provide SQL syntax highlighting for the query editor.
Package highlight wraps the Chroma v2 PostgreSQL lexer to provide SQL syntax highlighting for the query editor.
gui/editor/sqlcontext
Package sqlcontext is the detection brain for schema-aware SQL completion.
Package sqlcontext is the detection brain for schema-aware SQL completion.
gui/grid
Package grid ...
Package grid ...
gui/internal/testfake
Package testfake supplies an in-memory GuiDriver fake used by tests in pkg/gui.
Package testfake supplies an in-memory GuiDriver fake used by tests in pkg/gui.
gui/keys
Package keys is the single call site for registering keyboard and mouse bindings with the gocui runtime.
Package keys is the single call site for registering keyboard and mouse bindings with the gocui runtime.
gui/modes
Package modes is intentionally empty.
Package modes is intentionally empty.
gui/orchestrator
Package orchestrator wires the pgsavvy TUI: it owns the focus-stack tree, the GuiDriver instance, every UI/data helper and controller, and the gocui MainLoop entry point.
Package orchestrator wires the pgsavvy TUI: it owns the focus-stack tree, the GuiDriver instance, every UI/data helper and controller, and the gocui MainLoop entry point.
gui/popup
Package popup ...
Package popup ...
gui/presentation
Package presentation supplies render-time helpers that derive border styling and header text from a *models.Connection, plus the closures the context layer consumes through ContextTreeDeps.
Package presentation supplies render-time helpers that derive border styling and header text from a *models.Connection, plus the closures the context layer consumes through ContextTreeDeps.
gui/services
Package services ...
Package services ...
gui/services/custom_commands
Package custom_commands ...
Package custom_commands ...
gui/status
Package status assembles the status-bar string rendered along the bottom of the gui.
Package status assembles the status-bar string rendered along the bottom of the gui.
gui/style
Package style ships a chainable TextStyle builder used across the gui rendering layer.
Package style ships a chainable TextStyle builder used across the gui rendering layer.
gui/types
Package types declares the foundational type system shared by every pkg/gui subpackage: ContextKind/ContextKey enums, the IBaseContext interface, the Views holder, focus/refresh option structs, the Mode bitmask, KeyBinding, the GuiCommon/HelperCommon aggregators, and the GuiDriver interface that abstracts the underlying gocui runtime.
Package types declares the foundational type system shared by every pkg/gui subpackage: ContextKind/ContextKey enums, the IBaseContext interface, the Views holder, focus/refresh option structs, the Mode bitmask, KeyBinding, the GuiCommon/HelperCommon aggregators, and the GuiDriver interface that abstracts the underlying gocui runtime.
i18n
Package i18n provides localized UI strings for pgsavvy.
Package i18n provides localized UI strings for pgsavvy.
jsonschema
Package jsonschema ...
Package jsonschema ...
logs
Package logs ...
Package logs ...
models
Package models ...
Package models ...
query
Package query ...
Package query ...
query/plandoctor
Package plandoctor is a pure, offline EXPLAIN-plan insight engine.
Package plandoctor is a pure, offline EXPLAIN-plan insight engine.
session
Package session resolves runtime credentials for database connection profiles and (in subsequent tasks) builds engine-specific connection configs.
Package session resolves runtime credentials for database connection profiles and (in subsequent tasks) builds engine-specific connection configs.
session/sshtunnel
Package sshtunnel opens a driver-agnostic SSH connection to a bastion and exposes a DialContext suitable for use as a database driver's dial function (e.g.
Package sshtunnel opens a driver-agnostic SSH connection to a bastion and exposes a DialContext suitable for use as a database driver's dial function (e.g.
tasks
Package tasks ...
Package tasks ...
theme
Package theme ...
Package theme ...
theme/builtin
Package builtin holds the bundled ThemeConfig presets shipped with pgsavvy.
Package builtin holds the bundled ThemeConfig presets shipped with pgsavvy.
update
Package update fetches the latest GitHub Release, selects the host's binary asset, downloads and verifies it against checksums.txt, and compares versions.
Package update fetches the latest GitHub Release, selects the host's binary asset, downloads and verifies it against checksums.txt, and compares versions.
utils
Package utils ...
Package utils ...

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL