SwissQL is a developer-focused, modern “database Swiss Army knife” that provides a unified CLI experience for connecting to and querying different databases through a lightweight backend service.
The MVP uses an HTTP/JSON (REST) protocol between the CLI and backend to keep local development and debugging simple, with a planned evolution path toward streaming and higher-performance protocols (e.g., gRPC).
- A Go-based CLI that provides a convenient command interface for database workflows.
- A Java 21 backend API that manages connections and executes SQL against target databases via JDBC.
- A forward-looking design for AI-assisted SQL generation and MCP-based extensibility (plugin-style routing), while keeping JDBC as the core execution path.
- CLI (Go)
- Command engine built with Cobra.
- Communicates with the backend via HTTP/JSON.
- Backend service (Java 21, Spring Boot)
- REST API layer.
- Connection/session management and JDBC execution.
- Uses HikariCP for JDBC connection pooling.
- Packs common database drivers in the service (Oracle and PostgreSQL are included in the Maven dependencies).
User -> swissql-cli (Go) -> HTTP/JSON -> swissql-backend (Java/Spring Boot) -> JDBC -> Database
- Start swissql-backend (Docker)
# Windows PowerShell example:
docker run -d --rm --name swissql-backend `
-p 8080:8080 `
ghcr.io/kamusis/swissql-backend- Connect from SwissQL CLI to a Oracle database via the backend
swissql connect "oracle://user:password@host:port/serviceName"- Connect from SwissQL CLI to a PostgreSQL database via the backend
# if Postgres runs on the host and backend runs in Docker, use host.docker.internal instead of localhost:
./swissql connect "postgres://postgres:postgres@host.docker.internal:5432/postgres"SwissQL provides a unified connmgr command system for managing database connection profiles in the REPL:
# Import DBeaver project connections
swissql> connmgr import -dbp /path/to/project.dbp
# List all profiles
swissql> connmgr listFeatures:
- Automatic database type detection and DSN conversion
- Profile name sanitization and conflict handling
- Secure credential handling (passwords not imported, prompted on first use)
- Support for various database types (Oracle, PostgreSQL, MySQL, SQL Server, DB2, Informix, etc.)
- Pattern-based profile removal with safety checks
- Database type filtering for bulk operations
SwissQL supports persistent connection profiles with encrypted credential storage:
# Connect using saved profile
swissql connect --profile my-oracle-db
# Or shorthand in REPL:
swissql> connect my-oracle-dbProfile Storage:
- Profiles:
~/.swissql/connections.json - Credentials:
~/.swissql/credentials.json(AES-CBC encrypted) - Automatic credential prompting and optional saving
SwissQL supports both built-in and directory-provided JDBC drivers:
Built-in Drivers:
- Oracle (ojdbc11)
- PostgreSQL (postgresql)
Directory-provided Drivers:
Place JDBC drivers and manifests in swissql-backend/jdbc_drivers/<db_type>/:
jdbc_drivers/
├── mysql/
│ ├── driver.json
│ └── mysql-connector-j-8.x.x.jar
├── sqlserver/
│ ├── driver.json
│ └── mssql-jdbc-12.x.x.jar
└── yashandb/
├── driver.json
└── yasdb-jdbc-23.x.x.jar
Driver Manifest Example:
{
"dbType": "mysql",
"aliases": ["mariadb"],
"driverClass": "com.mysql.cj.jdbc.Driver",
"jdbcUrlTemplate": "jdbc:mysql://{host}:{port}/{database}",
"defaultPort": 3306
}- Enable AI features (Docker Compose + Docker secrets)
If you want to use /ai ..., you can enable the AI gateway by providing a few configuration values as Docker secrets (no application.properties file and no /config mount required).
Recommended workflow (you can do this in any folder on your machine):
- Create a working directory (example name:
swissql-backend) andcdinto it. - Create the 3 secret files under
./secrets/. - Create
docker-compose.ymlin the same directory. - Start the container.
Example (Windows PowerShell):
# 1) Create a working directory anywhere
mkdir swissql-backend
cd swissql-backend
# 2) Create secrets (files contain ONLY the raw value, no KEY= prefix)
mkdir secrets
# For OpenAI-compatible providers (openai, deepseek, etc.)
Set-Content -NoNewline -Path .\secrets\SWISSQL_AI_PROVIDER -Value "openai"
Set-Content -NoNewline -Path .\secrets\OPENAI_API_KEY -Value "<your_openai_api_key>"
Set-Content -NoNewline -Path .\secrets\OPENAI_MODEL -Value "<your_model>"
# For Portkey (alternative provider)
# Set-Content -NoNewline -Path .\secrets\PORTKEY_API_KEY -Value "<your_portkey_api_key>"
# Set-Content -NoNewline -Path .\secrets\PORTKEY_VIRTUAL_KEY -Value "<your_portkey_virtual_key>"
# Set-Content -NoNewline -Path .\secrets\PORTKEY_MODEL -Value "<your_model>"
# 3) Create docker-compose.yml (see below)
# 4) Start
docker compose up -ddocker-compose.yml example (saved next to the secrets/ folder):
services:
swissql-backend:
image: ghcr.io/kamusis/swissql-backend:latest
container_name: swissql-backend
ports:
- "8080:8080"
secrets:
- SWISSQL_AI_PROVIDER
- OPENAI_API_KEY
- OPENAI_MODEL
# For Portkey (alternative provider), uncomment and use these instead:
# - PORTKEY_API_KEY
# - PORTKEY_VIRTUAL_KEY
# - PORTKEY_MODEL
secrets:
SWISSQL_AI_PROVIDER:
file: ./secrets/SWISSQL_AI_PROVIDER
OPENAI_API_KEY:
file: ./secrets/OPENAI_API_KEY
OPENAI_MODEL:
file: ./secrets/OPENAI_MODEL
# For Portkey (alternative provider), uncomment and use these instead:
# PORTKEY_API_KEY:
# file: ./secrets/PORTKEY_API_KEY
# PORTKEY_VIRTUAL_KEY:
# file: ./secrets/PORTKEY_VIRTUAL_KEY
# PORTKEY_MODEL:
# file: ./secrets/PORTKEY_MODELFor additional (optional) settings, see the AI setup section below.
- Mounting Oracle wallets folder
If you are connecting to an Oracle instance in OCI (for example, Autonomous Database), you typically need an Oracle client wallet (mTLS) in order to authenticate and connect. In that case, you must mount the wallet directory into the container, and set TNS_ADMIN to the wallet path inside the container (for example, /wallets/ora1). You can mount multiple wallet directories at the same time (for example, /wallets/ora1, /wallets/ora2) and connect to different Oracle instances by setting TNS_ADMIN accordingly in each CLI connection string.
docker-compose.yml example (AI secrets + multiple wallet mounts):
services:
swissql-backend:
image: ghcr.io/kamusis/swissql-backend:latest
container_name: swissql-backend
ports:
- "8080:8080"
volumes:
- "/path/to/Wallet1_OCI:/wallets/ora1:ro"
- "/path/to/Wallet2_OCI:/wallets/ora2:ro"
secrets:
- PORTKEY_API_KEY
- PORTKEY_VIRTUAL_KEY
- PORTKEY_MODEL
secrets:
PORTKEY_API_KEY:
file: ./secrets/PORTKEY_API_KEY
PORTKEY_VIRTUAL_KEY:
file: ./secrets/PORTKEY_VIRTUAL_KEY
PORTKEY_MODEL:
file: ./secrets/PORTKEY_MODELNote for Windows users: When specifying volume paths in
docker-compose.yml, use single quotes (e.g.,'C:/path/to/wallet') or forward slashes to avoid issues with YAML parsing backslashes.
docker compose up -dConnect from SwissQL CLI to the Oracle instance in OCI via the backend
# Oracle (OCI) via mounted wallet (TNS_ADMIN points to the container path):
./swissql connect "oracle://user:password@aora23ai_high?TNS_ADMIN=/wallets/ora1"The backend currently implements the following REST endpoints:
- Health
GET /v1/status
- Sessions
POST /v1/connect(returnssession_id)POST /v1/disconnect?session_id=...GET /v1/sessions/validate?session_id=...
- SQL execution
POST /v1/execute_sql
- Collectors (YAML-defined tools)
GET /v1/collectors/list?session_id=...GET /v1/collectors/queries?session_id=...&collector_id=...POST /v1/collectors/run
- Samplers (session-scoped resources)
PUT /v1/sessions/{session_id}/samplers/{sampler_id}DELETE /v1/sessions/{session_id}/samplers/{sampler_id}GET /v1/sessions/{session_id}/samplersGET /v1/sessions/{session_id}/samplers/{sampler_id}GET /v1/sessions/{session_id}/samplers/{sampler_id}/snapshot
- Metadata helpers
GET /v1/meta/list?session_id=...&kind=table|view&schema=...GET /v1/meta/describe?session_id=...&name=...&detail=fullGET /v1/meta/conninfo?session_id=...POST /v1/meta/explain(supportsanalyze)
- Autocomplete / completions
GET /v1/meta/completions?session_id=...&kind=schema|table|column&schema=...&table=...&prefix=...
- AI assistance
POST /v1/ai/generate(generates SQL JSON; does not execute)GET /v1/ai/context?session_id=...&limit=...POST /v1/ai/context/clear
- Driver management
GET /v1/meta/drivers(list loaded JDBC drivers)POST /v1/meta/drivers/reload(reload drivers from directory)
The CLI currently provides an interactive REPL with the following commands:
- CLI
help(show help)detach(leave REPL without disconnecting)exit | quit(disconnect backend session and remove it from registry)set display wide|narrow(toggle truncation mode)set display expanded on|off(expanded display mode)set display width <n>(set max column width)set output table|csv|tsv|json(set output format)connmgr import -dbp(import DBeaver .dbp project connections)connmgr list(list saved connection profiles with filtering)connmgr show(show profile details)connmgr remove(remove connection profiles)connmgr update(update existing profiles)
- psql-compat (\)
\conninfo(show current session and backend information)\d <name>(alias:desc) (describe a table/view)\d+ <name>(alias:desc+) (describe with more details)\dt | \dv(list tables/views)\explain <sql>(aliases:explain,explain plan for) (show execution plan)\explain analyze <sql>(alias:explain analyze) (show actual execution plan; executes the statement)\top(render latest sampler snapshot fortop)\sampler <action> <sampler_id>(control samplers)\swiss list(list available collectors)\swiss list queries [--collector=<collector_id>](list runnable queries underqueries:blocks)\swiss run <query_id> [--param=value](run a query; auto-resolve collector)\swiss run <collector_id|collector_ref> <query_id> [--param=value](run a query; explicit collector)\watch <command>(repeatedly execute a command (e.g.,\watch top))\i <file>(alias:@<file>) (execute statements from a file)\x [on|off](expanded display mode)\o <file>(redirect query output to a file)\o(restore output to stdout)
- AI (/)
/ai <prompt>(generate SQL via AI and confirm before execution)/context show(show recent executed SQL context used by AI)/context clear(clear AI context)
Note
If you are not a developer, you can stop here. The content below is mainly for contributors/developers.
This repository is intentionally structured as a multi-client architecture (today: CLI; future: GUI).
The most important rule:
- DO NOT IMPLEMENT BUSINESS LOGIC IN THE CLI !! All business logic must be designed and implemented as backend APIs first. The CLI is only a thin client responsible for calling backend APIs and presenting results in the terminal.
This keeps the domain logic centralized and makes it straightforward to add additional clients (for example a GUI) without re-implementing logic.
- Go: 1.23.x (see
swissql-cli/go.mod) - Java: 21 (see
swissql-backend/pom.xml) - Maven: 3.8+ recommended
- Access to a target database (e.g., Oracle or PostgreSQL) and credentials.
git clone <your-github-repo-url>From the repository root, build and run:
mvn -f swissql-backend/pom.xml -DskipTests package
mvn -f swissql-backend/pom.xml spring-boot:runThe backend should start on localhost (see Spring Boot defaults / project configuration).
If you want to use the local configuration, set the SPRING_PROFILES_ACTIVE environment variable to local before starting the backend:
$env:SPRING_PROFILES_ACTIVE = "local"You can verify it via:
curl http://localhost:8080/v1/statusBuild the CLI:
cd swissql-cli
go build -o swissql.exe .Run:
./swissql.exe --help- Start the backend service.
- Use the CLI commands to:
- Connect to a DB (backend creates a session).
- Execute SQL using the returned session.
The backend can generate SQL from natural language via an OpenAI-compatible gateway. Supports multiple providers: Portkey (default), OpenAI, DeepSeek, and other OpenAI-compatible providers. If AI is not configured, the endpoint still exists but returns an "AI generation is disabled" response.
Where to store configuration locally:
- Option A (recommended for local dev): use
swissql-backend/src/main/resources/application-local.properties(gitignored) and keep secrets out of Git.- A committed template is available at
swissql-backend/src/main/resources/application-example.properties.
- A committed template is available at
- Option B: export environment variables in your shell before starting the backend.
Enable the local Spring profile (PowerShell) before starting the backend:
$env:SPRING_PROFILES_ACTIVE="local"Choose your AI provider by setting the SWISSQL_AI_PROVIDER environment variable (default: openai).
Option 1: OpenAI-compatible providers (recommended)
Set SWISSQL_AI_PROVIDER to your provider name (e.g., openai, deepseek).
Required environment variables:
{PROVIDER}_API_KEY(e.g.,OPENAI_API_KEY,DEEPSEEK_API_KEY){PROVIDER}_MODEL(e.g.,OPENAI_MODEL,DEEPSEEK_MODEL)
Optional environment variables:
swissql.ai.{provider}.base-url(e.g.,swissql.ai.openai.base-url)swissql.ai.{provider}.timeout-ms(e.g.,swissql.ai.openai.timeout-ms)
Example for OpenAI:
$env:SWISSQL_AI_PROVIDER = "openai"
$env:OPENAI_API_KEY = "sk-..."
$env:OPENAI_MODEL = "gpt-4"Example for DeepSeek:
$env:SWISSQL_AI_PROVIDER = "deepseek"
$env:DEEPSEEK_API_KEY = "sk-..."
$env:DEEPSEEK_MODEL = "deepseek-chat"Option 2: Portkey (alternative provider)
Set SWISSQL_AI_PROVIDER to portkey.
Required environment variables:
PORTKEY_API_KEYPORTKEY_VIRTUAL_KEY(orPORTKEY_VIRTUAL_KEY_<PROFILE>)PORTKEY_MODEL(orPORTKEY_MODEL_<PROFILE>)
Optional environment variables:
PORTKEY_PROFILE(e.g.DEV,PROD)PORTKEY_BASE_URL(orPORTKEY_BASE_URL_<PROFILE>, defaults tohttps://api.portkey.ai)PORTKEY_TIMEOUT_MS(request timeout in milliseconds, defaults to30000)
Profile example (PORTKEY_PROFILE=DEV):
PORTKEY_VIRTUAL_KEY_DEV=...PORTKEY_MODEL_DEV=...- (optional)
PORTKEY_BASE_URL_DEV=...
The design document defines the Oracle DSN semantics as:
- Service name:
oracle://user:password@host:port/serviceName
- SID (via query parameter):
oracle://user:password@host:port/?sid=ORCL
For Oracle Cloud / Autonomous Database connections using a Wallet (TNS alias), the backend also supports passing TNS_ADMIN as a query parameter. The host part is treated as the TNS alias (for example ora23ai_high).
Example:
oracle://user:password@ora23ai_high?TNS_ADMIN=/path/to/Wallet_ORA23AI
Note: if your wallet path contains spaces or special characters, URL-encode the value (e.g., replace spaces with %20). The backend URL-decodes DSN query parameters such as TNS_ADMIN.
If your username/password contains URL-reserved characters (for example @, :), URL-encode them as well.
swissql-cli/ # Go CLI
swissql-backend/ # Java 21 Spring Boot backend
- The protocol and endpoints are designed for an MVP-friendly REST API and may evolve.
- Do not commit credentials. Use environment variables, stdin-based password input, or your OS keychain (planned).