- Go 99.5%
- Nix 0.4%
- JavaScript 0.1%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| .opencode | ||
| cmd | ||
| docs | ||
| internal | ||
| readme | ||
| scripts/release | ||
| .envrc | ||
| .gitignore | ||
| .goreleaser.darwin.yml | ||
| .goreleaser.yml | ||
| AGENTS.md | ||
| devenv.lock | ||
| devenv.nix | ||
| devenv.yaml | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| README.md | ||
| VERSION | ||
Tonic
Status: Alpha
tonic is a terminal-first database workspace for explicit SQL execution against saved targets.
It starts with a CLI, and now also exposes the first local service boundary over stdio so editor integrations can build on the same execution model.
Tonic stands for Tiny Octopus Navigating Infinite Catalogs. Why?... Why not?
Install
Homebrew
brew tap fairlabs/tap https://forgejo.fairlabs.dev/fairlabs/homebrew-tap.git
brew install tonic
Nix
nix profile install git+https://forgejo.fairlabs.dev/fairlabs/tonic.git
Run without installing:
nix run git+https://forgejo.fairlabs.dev/fairlabs/tonic.git
What It Is
The current shape of tonic is:
- saved local database targets
- explicit execution from inline SQL and query files
- file-scoped session metadata for multi-target workflows
- one shared runtime for CLI execution and the local
serveboundary
tonic is not an ad hoc connection-string runner. Execution starts from a saved named target in effective config, then uses a consistent target-resolution and session model across commands.
Effective config means:
- global config from
$XDG_CONFIG_HOME/tonic/config.yamlor~/.config/tonic/config.yaml - optional local override config from
<repo-root>/.tonic/config.yamlwhen running inside a git repo, or./.tonic/config.yamloutside a repo - local connections replace same-named global connections as whole entries
- other config keys such as
inspect_cachemerge field-by-field
Current CLI Surface
connections
tonic connections add postgres NAME [--local]tonic connections add snowflake NAME [--local]tonic connections add sqlite NAME [--local]tonic connections add mysql NAME [--local]tonic connections add duckdb NAME [--local]tonic connections show [NAME]tonic connections edit [--local]
config
- reserved for future CLI configuration
query
tonic query ping --target NAMEtonic query exec --target NAME --sql '...'tonic query exec --file path.sql
inspect
tonic inspect catalogs --target NAMEtonic inspect namespaces --target NAMEtonic inspect tables --target NAMEtonic inspect views --target NAMEtonic inspect view-definition OBJECT --target NAMEtonic inspect columns OBJECT --target NAMEtonic inspect ddl OBJECT --target NAME --type ...
serve
tonic serve --stdio
serve now exposes the first local JSON-RPC boundary over stdio. It reuses the same target resolution, inspection behavior, artifact parsing, and execution rules as the CLI.
Inspect requests served through serve now use tonic-owned persistent metadata caching with config-driven TTLs, and support explicit live refetch via the optional refresh=true request field on inspect methods.
What Works Today
- saved Postgres, Snowflake, MySQL, SQLite, and DuckDB targets
- connectivity and context checks with
query ping - inline SQL execution with
query exec --sql - query-file execution with
query exec --file - catalog inspection with
inspect - Snowflake inspect descriptions from object comments
table,csv, andjsonoutputtextandjsonoutput for definitions and DDL- reusable primary and handle-bound file sessions
- file directives with
tonic-file,tonic-bind,tonic, and printabletonic-printreport comments - write statements, explicit transaction control, and
--autocommit on|off - explicit statement permissions with inherited global defaults and per-target allow/deny overrides
- explicit supported statement matching for
select, DML, broad DDL actions,truncate, Snowflakecopy, transaction control, and registered read-like/provider-specific statements such asshow,describe,explain,values,call,merge, andreplace - opt-in Snowflake
browserauthcredential caching with one automatic retry when a stale cached login needs a fresh browser auth flow - local stdio JSON-RPC service methods for targets, query execution, artifact planning, catalog inspection, and reusable sessions
inspect currently supports:
- catalogs, namespaces, tables, views, view definitions, and table columns on Postgres and Snowflake
- catalogs, tables, views, view definitions, and table columns on MySQL
- namespaces, tables, views, view definitions, and table columns on SQLite
- catalogs, namespaces, tables, views, view definitions, and table columns on DuckDB
- descriptions for Snowflake catalogs, namespaces, tables, views, and columns
- descriptions from DuckDB comments where DuckDB exposes them in metadata functions
- DDL for catalogs, namespaces, tables, and views on Snowflake
- DDL for tables and views on MySQL and SQLite
- DDL for tables and views on DuckDB
- unquoted object references in
name,namespace.name, andcatalog.namespace.nameforms
For file execution, tonic already supports reusable transaction-aware sessions with:
- file default sessions
- handle-bound sessions
- ephemeral one-off statement overrides
- explicit
begin,commit,rollback,savepoint,release, androllback to
Query Files
tonic query files let the SQL artifact describe how statements resolve targets and sessions.
Example:
-- tonic-file: target=warehouse context.schema=analytics autocommit=off
-- tonic-bind: handle=writer target=warehouse context.schema=public autocommit=off
select * from reports.daily_sales;
-- tonic: handle=writer
update reports.job_state set last_run_at = now() where name = 'daily_sales';
Query files can also emit report text without sending comments to the database:
-- tonic-print: # Daily sales report
-- tonic-print:
-- tonic-print-begin
-- ## Notes
--
-- - Human-readable context before results
-- tonic-print-end
select * from reports.daily_sales;
This is the core product direction: explicit query artifacts with local saved targets, predictable session behavior, and report-friendly output.
Inspect Cache
Inspect metadata is cached persistently in tonic using a local SQLite database. The cache is lazy-populated from inspect calls, shared across clients, and governed by effective tonic config.
Default behavior:
- inspect metadata is reused from cache when it is still fresh
- the default TTL is
168h(7 days) tonic inspect ... --refreshforces a live refetch and overwrites the cached valuetonic serveinspect requests acceptrefresh=truefor the same bypass semantics
Example tonic config:
version: 2
inspect_cache:
path: /home/you/.local/state/tonic/inspect-cache.db
ttl: 168h
Near-Term Direction
The next layers on top of this core are:
- reusable inline sessions across separate CLI invocations
- expanding the
serveruntime beyond the first stdio JSON-RPC surface - editor, agent, and TUI clients built on that shared runtime
Docs
The docs site is the user-facing source of truth for install, configuration, command usage, query files, inspection, service methods, and backend support.
Last Change
0.8.2: Added Snowflake COPY INTO statement support