A terminal-native database IDE. Keyboard-first, async, pluggable.
Project description
Teridex 📟
A terminal-native database IDE. Keyboard-first, async, pluggable.
Teridex is a TUI database client built on a clean async core and a plugin-first architecture. It combines a rich query editor, lazy schema browser, virtualized result tables, and a fuzzy command palette — all inside your terminal.
✨ Key Features
- ⚡ Asynchronous Execution: Multi-threaded, fully cancellable database queries. Long-running queries won't block the TUI layout or cursor.
- ⌨️ Keyboard-First Design: Optimized for hands-on-keyboard speed. Support for both standard and Vim-style keybindings.
- 🔌 Pluggable Architecture: Easily write plugins to add custom panels, new commands to the palette, or listen to event hooks.
- 🗃️ Built-in Database Drivers: First-class support for DuckDB, SQLite, PostgreSQL, and MySQL.
- 📝 Rich Workspace Layout:
- Live Schema Tree: Real-time introspection of schemas, tables, columns, indexes, and foreign keys.
- Multi-Tab SQL Editor: Edit multiple queries side-by-side with SQL syntax highlighting.
- Interactive Results Table: Search, filter, and scroll through large result sets cleanly using pagination/batch loading.
- Command Palette: Quick actions, screen switching, and plugin commands.
- ⚙️ Configuration Layer: Customize the look and feel (including Monokai and Nord themes) and define saved connections.
📐 Package Architecture & Layering
Teridex follows a clean, layered architecture with strict dependency boundaries:
graph TD
core["teridex-core (Pure Domain)"]
adapters["teridex-adapters (DB Drivers)"]
plugins["teridex-plugins (Plugin API)"]
engine["teridex-engine (Orchestration)"]
tui["teridex-tui (Textual TUI)"]
cli["teridex-cli (Typer CLI)"]
adapters --> core
plugins --> core
engine --> adapters
engine --> plugins
tui --> engine
cli --> engine
[!IMPORTANT] Dependency Isolation: Inner packages must never depend on outer packages. Specifically,
teridex_corehas no dependencies on any other internal package. These boundaries are strictly verified viamypy --strict.
🚀 Getting Started
Prerequisites
- Python >= 3.13
- The
uvpackage manager (recommended) or standardpip.
Installation
Install Teridex using uv or standard Python package managers:
# Install core package
pip install teridex
# Install with support for all database drivers (Postgres, MySQL, SQLite, DuckDB)
pip install "teridex[all]"
# Install with specific drivers
pip install "teridex[postgres]"
pip install "teridex[duckdb]"
Alternatively, clone the repository for local development:
git clone https://github.com/salvatorecorvaglia/teridex.git
cd teridex
./scripts/dev.sh
Running the TUI
Start the workspace by pointing it to a database DSN (Data Source Name):
# Open with a temporary in-memory DuckDB
teridex tui --dsn duckdb:///:memory:
# Connect to a local SQLite database file
teridex tui --dsn sqlite:///path/to/database.db
# Connect to a PostgreSQL instance
teridex tui --dsn postgresql://user:password@localhost:5432/mydatabase
One-Shot CLI Execution
Run query statements directly from the command line and view results rendered as a styled table:
teridex run --dsn duckdb:///:memory: "SELECT 'Hello, Teridex!' AS message"
⚙️ Configuration
Configure Teridex via the config file located at ~/.config/teridex/config.toml.
Refer to the config.example.toml file for available options:
[ui]
theme = "monokai" # "monokai" (warm) or "nord" (cool)
keymap = "default" # "default" or "vim"
show_status_bar = true
row_batch_size = 1000 # Rows per batch to fetch from adapters
[engine]
default_timeout_seconds = 60.0
max_history_entries = 1000
pool_size = 5
[logging]
level = "INFO"
[plugins]
enabled = [] # Specify IDs of plugins to load (empty loader registers all)
disabled = [] # Specify IDs of plugins to exclude
Environment Overrides
You can override configuration keys using environment variables using the structure: TERIDEX_<SECTION>__<FIELD>.
For example:
TERIDEX_UI__THEME=nord teridex tui
🔌 Extensibility: Writing Plugins
Plugins are discovered using Python entry points registered under the teridex.plugins group in your package's metadata.
A plugin needs to implement the Plugin protocol.
1. Define the Manifest and Hooks
Create a class with a manifest property, on_load, and on_unload methods:
from teridex_plugins import PluginContext, Command, hook
from teridex_core.protocols.plugin import PluginManifest
class MyPlugin:
manifest = PluginManifest(
id="custom-notifier",
name="Custom Notifier",
version="0.1.0",
description="Warns users when executing risky SQL queries.",
requires_teridex=">=0.1.0"
)
def on_load(self, ctx: PluginContext) -> None:
# Register command palette action
ctx.register_command(
Command(
id="notify-hello",
title="Hello Notifier",
handler=self.hello_handler,
default_binding="ctrl+h"
)
)
ctx.logger.info("Custom Notifier plugin successfully loaded!")
def on_unload(self, ctx: PluginContext) -> None:
ctx.logger.info("Custom Notifier plugin unloaded.")
async def hello_handler(self, ctx: PluginContext) -> None:
ctx.publish(SomeNotificationEvent("Hello from plugin!"))
@hook("query.before_execute")
async def warn_on_drop(self, ctx: PluginContext, sql: str) -> None:
if "drop table" in sql.lower():
ctx.logger.warning("Risky query detected!", sql=sql)
Refer to api.py and context.py for the complete plugin-facing API surface.
🛠️ Extensibility: Custom Database Adapters
Add adapters by subclassing AbstractAdapter:
- Subclass
AbstractAdapterand set the driver names and URL schemas. - Implement
_do_connect,_do_close,ping,execute,stream,begin, andintrospect. - Register your driver class in registry.py.
🛠️ Local Development & Testing
We provide helper scripts inside the scripts/ directory to run checks, tests, and formatting easily:
- Run All Quality Gates:
./scripts/check.sh(Runs linting, typing, formatting, and unit tests). - Format Code:
./scripts/fmt.sh(Using Ruff). - Lint & Type Checking:
./scripts/lint.sh(Ruff and Mypy strict). - Unit Tests:
./scripts/test.sh(Pytest).
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
🔐 Security
If you discover a security vulnerability, please see our Security Policy.
📝 License
Distributed under the MIT License. See LICENSE for more information.
Author: Salvatore Corvaglia
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file teridex-0.1.0.tar.gz.
File metadata
- Download URL: teridex-0.1.0.tar.gz
- Upload date:
- Size: 156.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4643d9977d1a2d6790a618dd460bf28c16912be1cf32c29dcfd66ccf561d9fb1
|
|
| MD5 |
bf6380a4ea213513080650477dedc485
|
|
| BLAKE2b-256 |
e0b154f066f0dcba06eb6f78418ed824c19513c3b64577bc4e96942cd84e5404
|
Provenance
The following attestation bundles were made for teridex-0.1.0.tar.gz:
Publisher:
release.yml on salvatorecorvaglia/teridex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
teridex-0.1.0.tar.gz -
Subject digest:
4643d9977d1a2d6790a618dd460bf28c16912be1cf32c29dcfd66ccf561d9fb1 - Sigstore transparency entry: 1784140439
- Sigstore integration time:
-
Permalink:
salvatorecorvaglia/teridex@ab21317385fcd907e565306d37b1dfcfc46ebff0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/salvatorecorvaglia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ab21317385fcd907e565306d37b1dfcfc46ebff0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file teridex-0.1.0-py3-none-any.whl.
File metadata
- Download URL: teridex-0.1.0-py3-none-any.whl
- Upload date:
- Size: 85.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60bbd47fe6193e90ef94b6b124b2e0b49f7ae120ccd0fb8d913aeaa147f771ab
|
|
| MD5 |
71eebc4046130a8b82bfad40439c5bd7
|
|
| BLAKE2b-256 |
4df16d8f76179d3a6a62521b4b03424b3f8107e4968a79fab6c502791a58820c
|
Provenance
The following attestation bundles were made for teridex-0.1.0-py3-none-any.whl:
Publisher:
release.yml on salvatorecorvaglia/teridex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
teridex-0.1.0-py3-none-any.whl -
Subject digest:
60bbd47fe6193e90ef94b6b124b2e0b49f7ae120ccd0fb8d913aeaa147f771ab - Sigstore transparency entry: 1784140707
- Sigstore integration time:
-
Permalink:
salvatorecorvaglia/teridex@ab21317385fcd907e565306d37b1dfcfc46ebff0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/salvatorecorvaglia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ab21317385fcd907e565306d37b1dfcfc46ebff0 -
Trigger Event:
push
-
Statement type: