creel

module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT

README

creel

A quick tour of creel, recorded with asciinema. Play it live and interactive: asciinema play demo.cast

A fast, memory-efficient SQL TUI for SQLite, MySQL, and PostgreSQL, written in Go.

Inspired by sqlit (Python/Textual), creel brings a vim-driven, keyboard-first workflow to browsing schemas, running queries, and editing data — all from the terminal.

Entity-relationship diagram of the bundled demo database

(demo/schema.sql — a small e-commerce schema; g R inside creel renders the interactive version.)

erDiagram
    users ||--o{ addresses   : has
    users ||--o{ orders      : places
    users ||--o{ reviews     : writes
    categories ||--o{ categories : "parent of"
    categories ||--o{ products   : contains
    products ||--o{ order_items : "ordered as"
    products ||--o{ reviews     : "reviewed in"
    orders ||--o{ order_items   : contains
    orders ||--o{ payments      : "paid by"

    users {
        INTEGER id PK
        TEXT    email
        TEXT    name
        TEXT    role
    }
    categories {
        INTEGER id PK
        TEXT    name
        INTEGER parent_id FK
    }
    products {
        INTEGER id PK
        TEXT    name
        REAL    price
        INTEGER category_id FK
    }
    addresses {
        INTEGER id PK
        INTEGER user_id FK
        TEXT    city
        TEXT    country
    }
    orders {
        INTEGER id PK
        INTEGER user_id FK
        TEXT    status
        REAL    total
    }
    order_items {
        INTEGER id PK
        INTEGER order_id FK
        INTEGER product_id FK
        INTEGER quantity
    }
    reviews {
        INTEGER id PK
        INTEGER user_id FK
        INTEGER product_id FK
        INTEGER rating
    }
    payments {
        INTEGER id PK
        INTEGER order_id FK
        TEXT    method
        REAL    amount
    }

Features

  • Three databases, one interface — connect to SQLite, MySQL, or PostgreSQL (with SSH tunneling for remote MySQL)
  • Secret storage — passwords and SSH passwords are stored in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) rather than plaintext config; falls back to plaintext on systems without a keychain
  • Vim-mode editor — normal/insert modes, motions (h/j/k/l, w/b), operators (dd, dw, x, D), yank/paste, and SQL autocompletion
  • Table browser — expand/collapse columns, inspect schemas, fuzzy-filter tables
  • Results grid — sort, filter, search, hide/show columns, follow foreign keys (g d), mark and bulk-delete rows
  • Relationship explorer (g r / :explore panel) — a docked panel that browses a row like a folder: an expandable object-graph tree of the focused row's inbound and outbound foreign keys, with a live per-edge count. Expand an edge () to see the related rows inline, expand a row to see its edges, and so on (depth-capped); Enter opens a node in the grid, collapses, r retargets. The panel stays open and re-roots as the cursor moves. Counts and child rows fan out concurrently across all three drivers
  • Static ERD (g R / :erd) — renders a graphical entity-relationship diagram in a scrollable panel: bordered table cards laid out in dependency-ranked columns with box-drawing arrows from each FK to the PK it references (◆ = PK, ◇ = FK). m toggles to the Mermaid erDiagram source; y/s copy/save the Mermaid (renders natively in GitHub/GitLab markdown). Navigate by mouse — hover a card to pop up a tooltip of the info it doesn't already show (an expanded card lists its FK references, e.g. user_id → users.id, which you'd otherwise trace an arrow for; a collapsed card reveals its hidden columns), click a card to highlight its relationships (dimming the rest), double-click to re-centre, or in a focused ERD click a related table's header (marked ) to re-focus on its neighbourhood — or by keyboard: j/k/h/l move a focus between cards (the viewport follows), Space highlights the focused card, Enter re-focuses the ERD on it, / jumps to a table by name (Tab cycles matches), p traces the shortest FK path between two tables (anchor one, move to the other, p again), zz fits all cards to the viewport, zc/zo/za collapse/expand/toggle a focused card to a header-only bar to declutter dense schemas (▸ marks a folded card), zM/zR collapse/expand every card at once (the layout contracts to reclaim the freed space, arrows re-route, and the view reframes), and g/G/ctrl+d/ctrl+u page the view
  • Inline editing — edit cells directly, insert rows, clone rows, paste from clipboard
  • Record inspector — side panel with a vertical form view that tracks the results cursor
  • Query history & bookmarks — per-connection, persisted, searchable
  • Session restore — reopening a connection brings back your open tabs and editor buffers from the last visit (keyed per connection + database). Buffers are restored but not re-executed; a creel -f startup file still takes precedence on first connect. :session clear wipes the saved snapshot, :session save snapshots now
  • EXPLAIN plans — driver-aware rendering (g e) of query plans
  • Schema editing — add columns, rename tables, create/drop/truncate tables, and a grid-based table designer (N)
  • Table structure view (d) — a tabbed structure editor: columns (editable grid), foreign keys, indexes, check constraints, and triggers in one view, plus a definition tab for views
  • Read-only mode — a per-connection readonly: true flag or a global --readonly CLI flag that rejects writes (INSERT/UPDATE/DELETE/DDL), blocks transactions and imports, and opens the connection read-only at the engine level (SQLite query_only, Postgres default_transaction_read_only); a READ-ONLY indicator shows in the status bar
  • Import / export — streaming SQL dump importer (I) and a pure-Go mysqldump-compatible exporter (X); result-set export via the g X dialog (format, columns, and whole-table/marked/page scope) or instant CSV (x)
  • Cross-table search (S) and column statistics (g s)
  • Command palette (Ctrl+P) and a full help overlay (?)
  • Pagination — large result sets are paged (LIMIT/OFFSET) for speed and low memory
  • CLI mode — run a query and print results without launching the TUI

Install

Homebrew (tap):

brew install rsiota/creel/creel

go install:

go install github.com/rsiota/creel/cmd/creel@latest

Requirements

  • Go 1.26+ (only needed to build from source)
  • A terminal with Unicode support

Build

git clone https://github.com/rsiota/creel.git
cd creel
go build -o creel ./cmd/creel/

Usage

Interactive TUI
./creel

On first run, no config exists — use the connection list (n to add) to create connections, which are saved to ~/.config/creel/config.yaml.

CLI mode

Execute a single query and print results as TSV:

./creel -e "SELECT * FROM users" -database /tmp/test.db
./creel -e "SHOW TABLES" -driver mysql -database myapp -host 10.0.0.5 -user admin -password secret

Flags:

Flag Description Default
-e SQL query to execute (enables CLI mode)
-driver sqlite, mysql, or postgres sqlite
-database Database name (SQLite path or MySQL/PG database)
-host Database host (MySQL/Postgres) localhost
-port Database port (MySQL/Postgres) 3306
-user Username (MySQL/Postgres) root
-password Password (MySQL/Postgres)
-cli Force CLI mode false
-version Print version information and exit

Configuration

Upgrading from gsql? On first launch creel automatically moves ~/.config/gsql/ to ~/.config/creel/ (connections, history, bookmarks, sessions) and keeps reading any keychain secrets stored under the old gsql service, so nothing needs to be re-entered. New secrets are written under the creel service going forward.

Connections are stored at ~/.config/creel/config.yaml. Secret fields (passwords) default to the OS keychain; in that case the config holds an opaque reference instead of the real password:

connections:
  - name: local-dev
    driver: sqlite
    database: /path/to/db.sqlite
  - name: staging
    driver: mysql
    database: myapp
    host: 10.0.0.5
    port: 3306
    username: admin
    password: secret://staging/password   # looked up in the OS keychain
    group: Work                            # optional folder in the connection list
  - name: prod-pg
    driver: postgres
    database: analytics
    host: db.internal
    port: 5432
    username: readonly
    password: secret://prod-pg/password
  # MySQL behind a bastion host
  - name: tunneled
    driver: mysql
    database: reports
    host: 10.0.0.20
    port: 3306
    username: admin
    password: secret://tunneled/password
    ssh_host: bastion.example.com
    ssh_port: 22
    ssh_user: deploy
    ssh_key_path: ~/.ssh/id_ed25519

A password: value that is not a secret:// reference is treated as plaintext and used directly, so existing configs keep working. Set the connection form's Secrets field to plain to opt out of the keychain for a specific connection.

Read-only mode

Point creel at production safely by marking a connection readonly: true (see the prod-pg example below) or launching with creel --readonly to force every connection read-only. In either case writes are refused — Exec/Execute return an error for INSERT/UPDATE/DELETE/DDL, Begin/Session (imports) are blocked — and the connection is opened read-only at the engine level where the driver supports it. A READ-ONLY badge appears in the status bar.

connections:
  - name: prod-pg
    driver: postgres
    database: analytics
    host: db.internal
    port: 5432
    username: readonly
    password: secret://prod-pg/password
    readonly: true
Connection groups

Give a connection a group to organize the connection list into collapsible folders (see the staging example above):

connections:
  - name: staging
    driver: mysql
    # ...
    group: Work
  - name: personal-db
    driver: sqlite
    database: ~/notes.db
    group: Personal

In the connection list, grouped connections render indented under ▾ Group headers (with a connection count), ungrouped ones lead under "Ungrouped", then named groups alphabetically. Press space (or tab) to fold/unfold the group under the cursor, or enter on a header to toggle it. Filtering (/) flattens the list to ranked matches regardless of groups. Connections with no group render exactly as before when none of your connections use groups.

AI assistant

The assistant panel (and the :ai command) turn a natural-language question into SQL using any OpenAI-compatible endpoint (OpenAI, z.ai, OpenRouter, Ollama, LM Studio, …). Configure it in-app from the assistant panel:

  • M opens the provider picker. From there n adds a provider, e edits the one under the cursor, d deletes it (a y/n prompt confirms first, like deleting a connection), and enter makes one the active default.
  • The add/edit form collects a Name, API Key, Base URL, and a Secrets toggle (keychain / plain). In keychain mode (the default) the API key is stored in the OS keychain as a secret:// reference — never written to the config file in plaintext — exactly like a connection password.
  • ctrl+t in the form probes the provider's /models endpoint and reports ✓ reachable or the real error (a valid key pointed at the wrong endpoint is the usual cause of a confusing "unauthorized").
  • m (from the panel) browses the models the active provider exposes and pins one as that provider's model:.

The same data lives under an ai: block if you prefer to hand-edit:

ai:
  default: openai
  providers:
    - name: openai
      api_key: secret://ai/openai/api_key   # keychain ref (set by the form)
      base_url: https://api.openai.com/v1   # optional; defaults to OpenAI
      model: gpt-4o-mini                     # optional; set via `m`

With no providers configured, creel falls back to environment variables (CREEL_AI_API_KEY / OPENAI_API_KEY / ZAI_API_KEY, and optionally CREEL_AI_BASE_URL / CREEL_AI_MODEL), so the panel works with zero config. The deprecated GSQL_AI_* equivalents are still honoured (in lower priority) for users upgrading from gsql.

Settings

Top-level app preferences live under a settings: block. All fields are optional and fall back to defaults when omitted:

Key Default Description
page_size 200 Rows fetched per page in results
query_timeout 30s Per-query deadline (friendly form: 2m, 1h30m, or a bare seconds int). off / none (or a negative value) disables the deadline entirely — esc still cancels
default_driver sqlite Driver pre-filled in the add-connection form
theme tokyo-night Palette: tokyo-night, gruvbox, nord, catppuccin, light + ~565 auto-derived from iTerm2-Color-Schemes (dracula, solarized, …). Unknown → default
icons unicode Glyph set for tree expand/collapse markers (sidebar, connection groups, relationship explorer). unicode uses portable triangles (▾/▸); nerdfont uses Nerd Font angle chevrons (U+F107/U+F105) — open, rotationally-symmetric like treemacs, but only renders correctly in a terminal running a Nerd Font. Unknown → default
transparent_background false By default creel fills the app background with the theme's bg colour (required for light themes to be readable). Set true to leave it unpainted so the terminal's own background / transparency shows through — at the cost of light themes looking wrong.
confirm_destructive true Destructive actions (drop table/database, truncate, delete rows, discard edits, drop column, delete provider/connection, clear history/bookmarks) prompt for confirmation. Set false to skip the prompts and run each action immediately.
settings:
  page_size: 500
  query_timeout: 1m
  default_driver: postgres
  theme: gruvbox
  icons: nerdfont
  confirm_destructive: false

query_timeout accepts values like 30s, 2m, 1h30m, or a bare number of seconds (45). An invalid value makes config load fail loudly rather than silently falling back. An unknown theme silently falls back to the default rather than blocking startup. (cursor_style is reserved for upcoming work.)

To experiment with themes live, press g c in the workspace to open the theme picker (a scrollable, filterable overlay — type to filter by name, / to preview); moving the selection re-themes the UI immediately, enter saves the choice to config, and esc reverts. The theme's background is painted too, so light themes preview correctly. See THIRDPARTY.md for theme attribution.

Keybindings

Press ? inside the TUI for the full overlay, or Ctrl+P for the fuzzy command palette.

Global
Key Action
ctrl+e / \ Run statement under cursor
ctrl+r Refresh schema & re-run query
esc / ctrl+c Cancel running query
ctrl+w Maximize / restore editor
ctrl+t Switch connection
ctrl+b Browse databases (MySQL)
ctrl+y Query history
ctrl+g Bookmarks
B Bookmark current query
ctrl+o Toggle record inspector
ctrl+h/j/k/l Move focus between panels
tab / shift+tab Cycle focus
ctrl+d / ctrl+u Next / previous page
ctrl+p Command palette
: Ex command line (:q, :sort, :goto, …)
g c Theme picker (live preview)
? Toggle help
q / ctrl+q Quit (not while editing)
Connections
Key Action
enter Connect to selected
n New connection
e Edit connection
d Delete connection
/ Filter connections

In the add/edit form:

Key Action
tab Next field
enter Save
ctrl+t Test connection (no save)
esc Cancel
Sidebar (Tables)
Key Action
j/k Move
g g / G Top / bottom
space Expand columns
enter / s SELECT * from table
d Structure (columns/indexes/FKs/checks/triggers)
a Add column
r Rename table
T Truncate table
D Drop table
N New table (grid editor)
X Export database
I Import SQL dump
S Cross-table search
/ Filter tables
Editor (Vim)
Key Action
i/a/o/A/O Enter insert mode
esc Normal mode
h/j/k/l, w/b Move
x / dd / dw / D Delete
y / p Yank / paste
ctrl+n Autocomplete
== Format SQL
Results
Key Action
h/j/k/l Move cursor
0 / $ First / last column
g g / G Top / bottom
/ Search all columns
g / Regex search
n / N Next / previous match
o Sort column
g s Column statistics
g e Explain query plan
g d Follow foreign key
g b Go back
g r Relationship explorer (row's FK graph)
g R Static ERD (table cards + arrows)
* Keep rows equal to cursor cell
! Hide rows equal to cursor cell
g f Filter column values
space Toggle row mark
F Filter by marked rows
C Clear marks
u Undo last filter
c Clear filters
V Visual mode (select range)
dd Delete marked or cursor row
e Edit cell
E Expand cell (large values)
ctrl+s Save edits
A Insert new row
D Discard edits
H Hide column
g H Show all columns
v Column visibility overlay
: Ex command line (:q, :sort, :goto, …; column jump in results)
y / p Copy cell / paste to cell
Y Copy rows as INSERT statements
P Clone marked/cursor row
x Export current page to CSV
g X Export dialog (format · columns · scope)

Architecture

cmd/creel/main.go        Entry point (TUI + CLI modes)
internal/db/            Database abstraction layer
  db.go                 DB interface + Connection wrapper
  sqlite.go             SQLite driver (modernc.org/sqlite, pure Go)
  mysql.go              MySQL driver
  postgres.go           PostgreSQL driver (pgx/v5)
  ssh_tunnel.go         SSH tunnel support
  dump.go / import.go   Export & streaming import
internal/config/        YAML config load/save
internal/secrets/       OS keychain secret store (secret:// refs + plaintext fallback)
internal/history/       Per-connection query history (JSON)
internal/session/      Per-connection workspace state — open tabs, restored on reconnect (JSON)
internal/bookmarks/     Saved queries
internal/ui/            Bubble Tea components
  app.go                Top-level Model (Elm-style state machine)
  query_editor.go       SQL editor with vim mode
  results_table.go      Results grid renderer
  sidebar / inspector / editor overlays
  registry.go           Single source of truth for keybindings
  palette.go            Fuzzy command palette (Ctrl+P)
Design notes
  • Driver interfaceinternal/db/db.go defines the DB interface; every driver implements it, so adding a new database is self-contained.
  • Elm architecture — the UI is an immutable state machine in app.go (stateConnectionsstateWorkspace), with focus cycling between panels.
  • Pure-Go SQLite — no CGO, which simplifies cross-compilation.
  • Keybinding registryregistry.go is the single source of truth for both the help overlay and the command palette, with a drift-detection test ensuring documented keys are actually wired.

License

MIT

Directories

Path Synopsis
cmd
creel command
genthemes command
Command genthemes derives creel color palettes from iTerm2-Color-Schemes (Windows Terminal JSON format) and emits a Go source file that registers them as generatedThemes in package ui.
Command genthemes derives creel color palettes from iTerm2-Color-Schemes (Windows Terminal JSON format) and emits a Go source file that registers them as generatedThemes in package ui.
internal
ai
Package ai provides a minimal client for natural-language-to-SQL via a hosted (or self-hosted) chat-completions API.
Package ai provides a minimal client for natural-language-to-SQL via a hosted (or self-hosted) chat-completions API.
db
secrets
Package secrets provides an OS keychain-backed secret store for connection credentials and AI provider API keys, with a transparent plaintext fallback.
Package secrets provides an OS keychain-backed secret store for connection credentials and AI provider API keys, with a transparent plaintext fallback.
session
Package session persists per-connection workspace state — the open tabs, their editor buffers, and which tab is active — so reopening a connection restores where the user left off.
Package session persists per-connection workspace state — the open tabs, their editor buffers, and which tab is active — so reopening a connection restores where the user left off.
ui
version
Package version reports the creel build version for :version and CLI use.
Package version reports the creel build version for :version and CLI use.

Jump to

Keyboard shortcuts

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