Skip to content

LuciusChen/clutch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

591 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

clutch — Interactive Database Client for Emacs

https://melpa.org/packages/clutch-badge.svg

Overview

An Emacs database client with an interactive data browsing UI. Supports MySQL and PostgreSQL through pure Elisp protocol packages, SQLite through Emacs built-in sqlite-* functions, MongoDB through the external mongodb.el native client, Redis through the external redis.el native client, plus Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, DuckDB, and generic JDBC URLs through a lightweight JVM sidecar (clutch-jdbc-agent, Java 17+).

Architecture diagrams are in docs/architecture.md, and module ownership is recorded in PRD.md. For Org-Babel integration, install the separate ob-clutch package.

docs/screenshots/clutch-overview.png

Backend Support

BackendSupport levelRequirements and notes
MySQLCore SQL supportValidated against MySQL 5.6, MySQL 8.0, and MariaDB 10.11
PostgreSQLCore SQL supportFunctional and compatible, with less daily-use coverage than MySQL
SQLiteCore SQL supportRequires Emacs 29.1+ built-in sqlite-* functions; no external dependencies
Oracle / SQL ServerCore SQL support via JDBCRequires Java 17+ and clutch-jdbc-agent.jar
DuckDBCore SQL model, generic JDBC entryInstall the DuckDB JDBC driver and connect with a jdbc:duckdb:... URL
MongoDBBasic native document support; optional SQL Interface surfaceNormal connections use external mongodb.el native protocol support plus Clutch’s MongoDB Shell / MQL helper query buffers; SQL Interface endpoints use :surface sql-interface and require the JDBC driver
RedisBasic key/value supportNormal connections use external redis.el native RESP support plus Clutch’s line-oriented Redis command buffers, key browsing, and type-aware value display
ClickHouse / Snowflake / Redshift / DB2 / generic JDBCBasic SQL / query-first supportUseful through JDBC, with backend-specific limits around edits, transactions, and dialect behavior

See docs/backend-support.org for the support-level policy and non-relational boundary.

Features

Native Backends

  • MySQL, PostgreSQL, and SQLite are supported without a sidecar process
  • MySQL and PostgreSQL use pure Elisp protocol implementations
  • SQLite uses Emacs 29.1+ built-in sqlite-* functions
  • For native backend protocol, TLS, timeout, and connection examples, see docs/native-backends.md

Interactive UI

  • Result browser: single-page table view, fixed clickable header/status line, horizontal scrolling, row numbers, sort indicators, and right-aligned numeric columns
  • Execution flow: run a region or statement, keep focus in the SQL buffer, refresh results below, and mark the last executed statement in the gutter
  • SQL editing workflow: record view, foreign-key navigation, staged insert/edit/delete, SQL preview, and guarded commit
  • Filtering and export: server-side WHERE filters, client-side fuzzy filters, ORDER BY sorting, horizontal paging, CSV/TSV/Org table copy/export, SQL INSERT/UPDATE copy/export for SQL results, and native document helper copy/export for MongoDB results
  • SQL intelligence: scoped table/column completion, Eldoc, object lookup, MySQL HELP lookup, and cache-first metadata loading that avoids blocking point motion
  • Connection feedback: per-connection consoles, persisted console contents, auto-reconnect, explicit schema-refresh states, transaction status, and a dedicated debug buffer
  • Stateful transient feedback: active auto-commit, filters, sort, copy refinement, result layout, staged mutation count, and Record field action are shown directly in their menus
  • Inspection and extension: JSON/XML/BLOB value viewers, live cell viewer, per-column display overrides, and context export for external assistants
  • REPL mode built on comint-mode, with SELECT results shown in the standard result browser instead of expanded inline in REPL history

Row identity support for staged UPDATE / DELETE:

BackendNo-primary-key support
MySQL nativenon-null unique keys; no physical row-locator fallback
PostgreSQL nativenon-null unique keys, then ctid for ordinary heap tables
SQLite nativenon-null unique keys, then rowid for tables not declared WITHOUT ROWID
Oracle JDBCnon-null unique keys, then ROWID
Other JDBC backendsnon-null unique keys only

Joined, grouped, derived, or otherwise ambiguous result sets remain read-only for staged UPDATE / DELETE unless clutch can identify a single source table and inject or read a matching row identity.

Documentation

  • Architecture guide — current module layers, backend/surface model, connection flow, query/object flow, and JDBC runtime diagrams.
  • Interactive client guide — key bindings, result workflows, object actions, REPL, transient menus, faces, timeouts, and customization.
  • Backend support levels — Core SQL, basic support, MongoDB SQL Interface, DuckDB, and Redis.
  • Native backend guide — MySQL, PostgreSQL, SQLite, SSH tunnels, TLS, timeout behavior, and backend-specific examples.
  • JDBC backend guide — JDBC driver setup, connection examples, Oracle notes, transaction behavior, and generic JDBC URLs.
  • Org-Babel guideob-clutch setup, source block examples, header arguments, and connection caching.
  • JDBC agent protocol — sidecar RPC protocol and implementation notes.

Requirements

  • Emacs 29.1+
  • MySQL 5.6+ / 8.x, PostgreSQL 12+, or SQLite 3 (via Emacs built-in)
  • MariaDB 10.11 has been live-validated through the native mysql backend; TLS with mysql_native_password has also been live-validated; other MariaDB versions are expected to be broadly compatible but are not yet part of the regular test matrix
  • Java 17+ for the JDBC backend (Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, DuckDB)

For MySQL-family servers, core functionality (connect/query/object workflow, editing, prepared statements, and clutch UI workflows) is expected to work on MySQL 5.6+ and on compatible MariaDB releases. Some newer server-side features remain version-specific:

  • MySQL 5.6 does not provide a native JSON column type
  • MariaDB exposes JSON as an alias over text with json_valid(...) checks
  • MariaDB 10.11 TLS has been validated with mysql_native_password; the older mysql_old_password plugin is not supported by the native client
  • newer auth plugins and TLS combinations vary by server family/version

Installation

Install clutch from MELPA or another package archive:

(package-install 'clutch)

Protocol packages are optional and backend-specific. clutch does not install every database protocol package up front, because many users only use one backend. Install the protocol package for each backend you configure:

BackendExtra Emacs package
:backend mysqlmysql.el
:backend pgpg.el / pg-el
:backend mongodbmongodb.el
:backend redisredis.el
:backend sqlitenone; Emacs 29.1+ built-in SQLite support
:backend jdbc / Oracle / SQL Server / ClickHouse / DB2 / DuckDBnone; uses the bundled JDBC adapter

If a configured backend’s protocol package is missing, clutch reports the missing package when connecting. Install that package with your package manager, ensure it is on load-path, then retry the connection; restarting Emacs is the safest way to clear stale autoload or native-compile state after installation.

JDBC support ships inside clutch itself, but the runtime still needs Java 17+ and clutch-jdbc-agent.jar. Individual JDBC databases may also need driver jars. For Org-Babel support, install the separate ob-clutch package.

For source checkouts, add clutch and any native protocol backend checkout you use to load-path explicitly:

(add-to-list 'load-path "/path/to/clutch")
(add-to-list 'load-path "/path/to/mysql.el") ; only for :backend mysql
(add-to-list 'load-path "/path/to/pg-el")    ; only for :backend pg
(add-to-list 'load-path "/path/to/mongodb.el") ; only for :backend mongodb
(add-to-list 'load-path "/path/to/redis.el") ; only for :backend redis
(require 'clutch)

Upgrading From Pre-Split Checkouts

This release separates protocol and Org-Babel packages from the main clutch package. If you are upgrading from an older checkout that bundled everything in one repository, this is a breaking packaging change:

  • mysql.el is no longer bundled in this repository. Install it separately for :backend mysql.
  • pg.el is no longer bundled in this repository. Install it separately for :backend pg.
  • mongodb.el is no longer bundled in this repository. Install it separately for :backend mongodb.
  • redis.el is a lazy optional protocol package. Install it separately for :backend redis.
  • ob-clutch.el is no longer bundled; install ob-clutch separately for Org-Babel source blocks.
  • Saved connections must specify :backend explicitly.

Interactive Client

Quick Start

1. Configure connections

(add-to-list 'load-path "/path/to/clutch")
(require 'clutch)

(setq clutch-connect-timeout-seconds 10
      clutch-read-idle-timeout-seconds 30
      clutch-query-timeout-seconds 20
      clutch-jdbc-rpc-timeout-seconds 15)

(setq clutch-connection-alist
      '(("dev-mysql"  . (:backend mysql
                          :host "127.0.0.1" :port 3306
                          :user "root" :password "test"
                          :database "mydb"
                          :connect-timeout 5
                          :read-idle-timeout 60))
        ("dev-pg"     . (:backend pg
                          :host "127.0.0.1" :port 5432
                          :user "postgres" :password "test"
                          :database "mydb"))
        ("prod-pg"    . (:backend pg
                          :host "pg.internal" :port 5432
                          :user "app" :database "appdb"
                          :ssh-host "bastion-prod"))
        ("remote-pg"  . (:backend pg
                          :host "127.0.0.1" :port 55433
                          :user "app" :database "appdb"
                          :tramp "/ssh:devbox:/workspace/"))
        ("dev-redis"  . (:backend redis
                          :host "127.0.0.1" :port 6379
                          :database 0))
        ("dev-sqlite" . (:backend sqlite
                          :database "/path/to/my.db"))))
  • Every entry must specify :backend (mysql, pg, sqlite, mongodb, redis, or a JDBC driver symbol such as oracle).
  • SQLite is local and file-based: only :database is required; use ":memory:" for a transient database. Do not combine SQLite with :ssh-host, :ssh-tunnel, or :tramp.
  • :password is optional for network backends; see Password Management for auth-source integration.
  • Network backends accept :connect-timeout and :read-idle-timeout. PostgreSQL and JDBC also accept :query-timeout; JDBC additionally accepts :rpc-timeout.
  • TLS can be enabled with :tls t. For explicit plaintext, prefer :ssl-mode disabled on MySQL and :sslmode disable on PostgreSQL.
  • :ssh-host and :tramp both create local forwards for structured :host / :port endpoints. :ssh-host uses a ~/.ssh/config host alias, while :tramp derives the origin from an ssh-like or container TRAMP directory. :tramp-default-directory remains accepted as a longer spelling.
  • Query-console SQL is saved by connection identity rather than saved connection name, so renaming a saved connection keeps the same console SQL.

JDBC backends use a driver symbol as :backend. See docs/jdbc-backend.org for supported databases and setup.

2. Open a query console

M-x clutch-query-console     ;; Select a saved connection, or press RET on an
                              ;; unmatched connection to create a temporary connection
M-x clutch-query-sqlite-file ;; Shortcut: select a SQLite file → opens a connected SQL console
                             ;; Header-line: MySQL[root@127.0.0.1:3306/mydb]
                             ;;         or PostgreSQL[postgres@127.0.0.1:5432/mydb]
                             ;;         or SQLite[my.db]

Repeated calls with the same name switch to the existing buffer instead of opening a new one. Use clutch-switch-console to jump between open consoles. clutch-query-console lists saved connections; pressing RET with no matching connection starts a temporary connection flow and opens a query console for it. SQLite is part of that flow and asks for a database file instead of host/user credentials. clutch-query-sqlite-file is the direct shortcut for local SQLite files. If no saved connections are configured, clutch-query-console starts the temporary connection flow immediately.

3. Write and execute SQL

SELECT * FROM users LIMIT 10;

Press C-c C-c to execute. If a region is selected, the selected SQL runs; otherwise the statement at point runs. Results appear in a split result buffer below.

4. Control transactions

For native MySQL and PostgreSQL, and for JDBC connections that run in manual-commit mode, clutch uses the same transaction keys:

  • C-c C-a toggles auto-commit when supported
  • C-c C-m commits
  • C-c C-u rolls back

SQLite does not expose these transaction controls; its console header omits the Tx segment.

Native MySQL maps C-c C-a to the server session’s autocommit flag directly. Native PostgreSQL uses a clutch-managed manual mode: enabling manual mode does not send BEGIN immediately, the first foreground statement opens the transaction lazily, and transactional DDL also counts as uncommitted work, so toggle/disconnect stays blocked until you commit or roll back.

Password Management

Connection entries may include :password, but auth-source is preferred. When :password is omitted, clutch resolves credentials through:

  • pass entries via auth-source-pass, matching the connection name suffix or an explicit :pass-entry
  • standard auth-source-search by :host, :user, and :port
  • an interactive read-passwd prompt as the final fallback
(require 'auth-source-pass)

(setq clutch-connection-alist
      '(("dev-mysql" . (:backend mysql
                         :host "db.example.com" :port 3306
                         :user "alice" :database "mydb"))))
pass insert mysql/dev-mysql   ;; or just: pass insert dev-mysql

For JDBC connections (including Org-Babel blocks), an explicit :pass-entry that resolves to no password now fails fast in Emacs instead of sending a null password to the driver. If you use pass, make sure auth-source-pass is enabled first.

See the auth-source manual for supported credential stores.

SSH Tunnels via ~/.ssh/config

For bastion-style access, add :ssh-host to a saved network connection:

("prod-pg" . (:backend pg
               :host "pg.internal" :port 5432
               :user "app" :database "appdb"
               :ssh-host "bastion-prod"))

Clutch opens a local SSH forward through your normal OpenSSH configuration. Use M-x clutch-prepare-ssh-host, or S from C-c ?, when the first SSH use needs host-key confirmation or a key passphrase. The batch tunnel itself uses non-interactive OpenSSH auth, so load keys into ssh-agent or configure AddKeysToAgent when needed.

Add :ssh-tunnel direct-first when the same profile should try a direct connection before falling back to SSH. SSH forwarding applies to structured :host / :port entries; opaque :url profiles, including JDBC and MongoDB URLs, still need manual tunnels or backend-level transport support. Backend-specific tunnel details live in docs/native-backends.md.

TRAMP-aware Connection Origin

Opening a TRAMP buffer does not globally change clutch. TRAMP is considered only when a connection is created, and the chosen origin is stored for later reconnect, completion, refresh, and query execution. Configure :tramp when a profile should always use a remote-machine or container endpoint:

("remote-pg" . (:backend pg
                 :host "127.0.0.1" :port 55433
                 :user "app" :database "appdb"
                 :tramp "/ssh:devbox:/workspace/"))

Without :ssh-host or :tramp, commands invoked from a TRAMP buffer can infer that buffer’s remote context. clutch-tramp-context-policy controls this:

  • nil: never infer TRAMP context
  • ask (default): ask before using the current TRAMP context
  • auto: use the current TRAMP context without asking

Supported origin types, container relay requirements, and forwarding limits are documented in docs/native-backends.md.

Working with SQL files

You can also open any .sql file, enable clutch-mode, and connect manually — the query console is not required.

1. Open a .sql file
2. M-x clutch-mode        — enable clutch (inherits sql-mode syntax/fontification)
3. C-c C-e                 — select a saved connection or enter params manually
                             Mode-line shows MySQL[root@127.0.0.1:3306/mydb]
4. C-c C-c                 — execute region, or the current statement/query at point

In ordinary clutch-mode or REPL buffers, C-c C-e keeps that generic connect flow: select a saved connection, or press RET with no matching connection to enter temporary params. For SQLite files, prefer M-x clutch-query-sqlite-file, or M-x clutch-query-console followed by RET with no matching connection and backend sqlite; both open a connected SQL console rather than using the database file buffer as the editor. In query-console buffers, C-c C-e reconnects the connection already associated with that console, without reopening the global connection picker. To switch to another saved or temporary connection, use M-x clutch-query-console.

For deeper troubleshooting, enable M-x clutch-debug-mode, reproduce the failure, then inspect *clutch-debug*. Enabling the mode starts a fresh capture window and creates that dedicated buffer automatically. It is the only supported debug UI, and it shows problem records, generated/internal SQL when relevant, recent redacted debug events, and JDBC stderr/debug payload when available.

To activate clutch-mode automatically for .sql files, add to your config:

(add-to-list 'auto-mode-alist '("\\.sql\\'" . clutch-mode))

.mysql files activate clutch-mode automatically without any configuration.

Interactive Client Guide

Detailed key bindings, result-browser workflows, object navigation, Embark integration, transient menus, faces, timeouts, and customization now live in docs/interactive-client.org.

Common entry points:

  • C-c C-c executes the region or statement at point
  • Standard completion completes SQL identifiers at point, including empty column positions; C-c TAB invokes it explicitly
  • M-. jumps SQL aliases to their statement definition; object lookup uses C-c C-d / C-c C-j
  • C-c ? opens the transient menu
  • Stateful transient entries highlight their current choice; unavailable actions stay visible but inapt when their surrounding context is still useful
  • C-c C-j starts the object workflow
  • RET opens record view from a result row
  • Pressing s cycles sorting for the result column at point; simple table results use server-side ORDER BY, while UNION, grouped, derived, and other non-rewritable results sort the current page locally. Use C to jump to another visible column first, or click a result header to cycle it
  • i, d, and C-c C-c stage and commit row changes in result buffers
  • C-c ' edits the current result cell; in that edit buffer, C-c C-n stages database NULL
  • M-x clutch-copy-context-for-agent copies SQL, table metadata, and the latest matching visible result sample as Markdown for an external agent; the same command is available as k in the main and result transients. Table metadata reuses the existing object describe path.

MongoDB Backend

MongoDB is basic native document support through mongodb.el: ordinary MongoDB deployments, supported MongoDB Shell / MQL helper commands, and shared object/result workflows. It is not a full mongosh JavaScript runtime. MongoDB SQL Interface stays on the same mongodb backend as :surface sql-interface and requires the JDBC sidecar plus MongoDB JDBC driver jar. See docs/mongodb-backend.org.

Redis Backend

Redis is basic key/value support through redis.el. It connects to ordinary Redis TCP endpoints, uses line-oriented clutch-redis-mode command buffers, and maps key browsing/type-aware reads into the shared Clutch grid. Redis support is intentionally basic: no SQL row editing, joins, row identity, transaction workflow, pub/sub loops, cluster management, or stream consumer workflows. See docs/backend-support.org and docs/native-backends.md for support boundaries.

JDBC Backend

JDBC support covers Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, MongoDB SQL Interface, DuckDB, and generic JDBC URLs through the clutch-jdbc-agent sidecar. For setup, driver installation, connection examples, backend-specific notes, and transaction behavior, see docs/jdbc-backend.org.

For the sidecar wire protocol and agent internals, see docs/jdbc-agent-protocol.md.

Org-Babel Integration

Org-Babel integration lives in the separate ob-clutch package and supports saved clutch connections plus MySQL, PostgreSQL, SQLite, and generic JDBC-backed clutch source blocks. For setup, block examples, header arguments, and connection caching, see docs/org-babel.org.

Timeouts, Interrupts, and Customization

Timeouts can be configured globally or per connection, and long-running queries can be interrupted with C-g. Backend-specific cancel behavior, debug workflow, result displayers, schema warmup, CSV encoding, and completion customization are documented in docs/interactive-client.org.

Native Backend Usage

For mysql, pg, and SQLite connection examples, TLS notes, timeout behavior, and helper APIs, see docs/native-backends.md.

Testing

Unit tests (no server required)

The non-live CI gate used by GitHub Actions can be run locally:

./test/run-ci.sh all

Default ERT runs intentionally skip live tests when database credentials are not set. Treat those runs as unit/regression coverage, not proof that real database workflows still work. External protocol packages and the Org-Babel bridge live in separate repositories and carry their own focused test suites.

Native live tests

./test/run-ci.sh native-live

The native live runner starts or reuses local containers and covers MySQL, PostgreSQL, and ordinary MongoDB native protocol connections against real databases. Other JDBC live suites remain environment-driven and are skipped by default. MongoDB SQL Interface JDBC live tests require a SQL Interface endpoint; ordinary MongoDB work uses the default mongodb document surface. Contributor release gates are listed in AGENTS.md §Pre-Commit Checklist.

Roadmap

  • AST-based SQL rewriting is deferred, not planned as a near-term feature. The current top-level clause scanner, direct LIMIT/OFFSET pagination, and conservative result capability checks cover known WHERE/filter/count/ pagination cases without making derived-table wrapping the default escape hatch. Revisit a full parser only if concrete rewrite bugs or optimization features justify the added complexity.

License

GPL-3.0-or-later. See LICENSE.

About

Interactive Emacs database client for MySQL, PostgreSQL, SQLite, MongoDB, Redis, and JDBC.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors