The Problem
Developers who need quick, interactive access to many different SQL engines often launch heavyweight GUIs or VS Code extensions. The latency of those tools and the friction of configuring connection strings impede rapid debugging or ad‑hoc data inspection, especially when working from a terminal‑only environment.
What This Does
sqlit provides a terminal‑UI (TUI) that discovers local Docker containers, reads OS key‑ring credentials, and talks to > 20 database drivers. The main entry point is sqlit/cli.py (calls main() at line 467) which builds the textual UI, loads saved connections from sqlit/domains/connections/store/connections.py, and dispatches actions through the core action system (sqlit/core/*).
Connection configuration lives in sqlit/domains/connections/domain/config.py, a hub module imported by 115 other files. Provider implementations (e.g., sqlit/domains/connections/providers/mysql/provider.py) expose a uniform adapter API used by the UI to open a DB cursor.
How It Is Wired
Execution starts in sqlit/cli.py → main(). main() constructs the textual app (sqlit/domains/shell/app/main.py) and registers commands. The most‑used internal functions are:
pause– called from 131 places (e.g., UI waiting states).query_one– 129 callers (fetch‑single‑row actions)._clear_leader_pending– 98 callers (leader‑key state cleanup).
main() → compose() (in sqlit/domains/shell/app/main.py:1172) builds the UI layout, then run_cli() (called 38 times) starts the event loop. User actions eventually invoke connect() (in sqlit/core/connection_manager.py) which:
- Calls
get_option→ reads configuration fromconfig.py. - Calls
_import_driver_module→ dynamically loads the provider package. - Opens a DB cursor (
cursor.execute) – the only direct database write/read path (70 functions).
File system interaction occurs via open() calls in main.py (e.g., loading historic queries) and write_restart_cache (writes a cache file). External commands are run from start → populate_credentials_if_missing → run_password_command (uses subprocess.run).
Import‑cycle analysis shows config.py, catalog.py, and model.py form a circular dependency (10 high‑severity cycles). Because config.py is the hub, any change there propagates to > 115 modules, raising the blast radius for refactors. The oversized file sqlit/domains/shell/app/main.py (1,310 lines) contains deep nesting (max depth 7) and broad exception handling, which together increase cognitive load and risk of hidden bugs.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/sqlit
cd sqlit
# Install dependencies (uv is declared in pyproject.toml)
uv pip install --editable . # or: pip install -e .
# Run the TUI
python -m sqlit.cli # entry point defined in sqlit/cli.py
Configuration files live under config/ (e.g., settings.template.json). The first run creates config/sqlit-config/settings.json where saved connections are stored. No additional environment variables are required unless you need to point to a custom key‑ring backend.
Real‑World Use
A developer working on a microservice can start sqlit inside their dev container, let the Docker discovery pick up the service’s Postgres container, and run ad‑hoc queries without leaving the terminal. The UI’s Vim‑style keybindings let them filter results, copy rows, and edit queries on the fly, accelerating debugging cycles.
Code Health & Issues
- High – Pin GitHub Actions –
.github/workflows/*.ymluses tag references (@v26,@v5). Replace with commit SHAs. - High – Discard exit codes –
.github/workflows/ci.ymlline 563 masks failures; let the step fail. - Medium – Least‑privilege GITHUB_TOKEN – no permissions block; add
permissions: contents: read. - Medium – No Dependabot – only one manifest (
pyproject.toml); add.github/dependabot.yml. - Medium – Unpinned base image –
tests/fixtures/d1/Dockerfileusesnode:20-slim; pin by digest. - Medium – No vulnerability scan – add
dependency-review-actionorosv-scanner. - Medium – Persist‑credentials true – checkout step keeps token; set
persist-credentials: false. - Medium – No non‑root user – Dockerfile runs as root; create an unprivileged user.
- Low – No job timeout – add
timeout-minutesto CI jobs.
Additional findings from static analysis: 10 import cycles, a hub module with 115 dependents, two oversized files, many bare except blocks, and file handles opened without context managers.
The Bottom Line
sqlit delivers a functional, multi‑engine TUI that fills a clear niche for terminal‑centric database work. The codebase is feature‑rich but suffers from architectural hotspots (import cycles, large monolithic files) and several CI hygiene gaps that should be addressed before heavy production use. Engineers comfortable navigating Python import graphs and willing to refactor the hub module will find it a solid foundation for rapid data access.