Irodori Table
Irodori Table is a fast, local-first database workbench. This site is the public user, developer, and contributor documentation.
Getting started
- Install guide — download and launch the desktop app
- First connection and query — connect, run SQL, and read the first result set
User guides
- Connections
- Query editor and Vim
- Results grid and export
- ERD and schema designer
- Import and Migration Studio
- Git, terminal, and search
- AI assist
Development
- Windows development — set up and run locally on Windows
- macOS development — set up and run locally on macOS
- Linux development — set up and run locally on Linux
- Extension development — build on the extension SDK
- Internationalization — UI languages and translation keys
- Development security
- Clean room
How it works
- Completion and AI strategy
- Data verification and migration
- Data-source coverage strategy
- Implementation architecture
- Local SQL generation
- Query plan explorer
- Integrated terminal
- Headless local data API
- Knowledge base
- Repository boundaries
Reference
- Data source support status
- Engine syntax reference — connection strings and engine quirks
- DB feature samples — runnable, per-engine samples
- Per-engine cheatsheets
- Distribution and updates
- Store and package registration
- Support · Privacy notice · Disclaimer
- Licensing
Planning
Install Guide
Irodori Table ships desktop installers from GitHub Releases. The latest public
release checked for this guide is v0.6.0, published on 2026-07-02:
https://github.com/hjosugi/irodori-table/releases
Use the newest release for normal desktop installs. cargo install does not
install the desktop application. It is only for the separate headless
irodori-server binary in irodori-kit.
This guide is for packaged desktop installs. Source build prerequisites and WebView troubleshooting live in the platform development guides: Windows, macOS, and Linux.
Quick terminal install
The shortest terminal path uses GitHub CLI. Install gh first if your shell
does not already have it. When no release tag is passed, gh release download
downloads assets from the latest release.
Linux: Debian or Ubuntu
tmp="$(mktemp -d)"
gh release download --repo hjosugi/irodori-table --pattern "*.deb" --dir "$tmp"
sudo apt install "$tmp"/*.deb
Linux: Fedora, RHEL, or compatible
tmp="$(mktemp -d)"
gh release download --repo hjosugi/irodori-table --pattern "*.rpm" --dir "$tmp"
sudo dnf install "$tmp"/*.rpm
Linux: portable AppImage
mkdir -p "$HOME/Applications"
gh release download --repo hjosugi/irodori-table --pattern "*.AppImage" --dir "$HOME/Applications"
chmod +x "$HOME/Applications"/Irodori*.AppImage
"$HOME/Applications"/Irodori*.AppImage
macOS
mkdir -p "$HOME/Downloads/irodori-table"
gh release download --repo hjosugi/irodori-table --pattern "*.dmg" --dir "$HOME/Downloads/irodori-table"
open "$HOME/Downloads/irodori-table"/*.dmg
Move Irodori Table to Applications from the mounted disk image. The current
preview release includes an Apple Silicon .dmg; use a source build for Intel
macOS until an Intel .dmg is published.
Windows PowerShell
$dir = New-Item -ItemType Directory -Force "$env:TEMP\irodori-table"
gh release download --repo hjosugi/irodori-table --pattern "*.msi" --dir $dir.FullName
$msi = Get-ChildItem $dir.FullName -Filter "*.msi" | Select-Object -First 1
Start-Process $msi.FullName -Wait
Downloads by OS
| OS | Recommended asset | Notes |
|---|---|---|
| Windows | .msi or setup .exe | Download the Windows installer asset and run it from Explorer. |
| macOS | .dmg | Open the disk image, move Irodori Table to Applications, then launch it. Current preview assets are Apple Silicon only. |
| Linux | .deb, .rpm, or .AppImage | Use .deb on Debian/Ubuntu-style systems, .rpm on Fedora/RHEL-style systems, or AppImage for portable local runs. |
Windows
- Download the Windows installer from the release assets.
- Run the installer.
- Launch Irodori Table from the Start menu.
If Windows SmartScreen appears for a development-preview build, verify that the installer came from the official GitHub release page before continuing.
macOS
- Download the
.dmgfrom the release assets. - Open the disk image and move Irodori Table into Applications.
- Launch it from Applications.
During the development-preview phase, macOS may require Control-click > Open the first time you run a downloaded build.
The current preview release publishes an Apple Silicon .dmg. Intel macOS users
should build from source until an Intel .dmg appears in the release assets.
Linux
For Debian or Ubuntu-style systems, download the .deb and install it with your
package manager:
sudo apt install ./path/to/downloaded-package.deb
For Fedora, RHEL, or compatible distributions, download the .rpm and install
it with your package manager:
sudo dnf install ./path/to/downloaded-package.rpm
For other desktop distributions, download the AppImage, make it executable, and run it:
chmod +x ./Irodori*.AppImage
./Irodori*.AppImage
Some distributions ship FUSE 3 by default while AppImage still expects FUSE 2. If the AppImage does not launch, either install the distribution’s FUSE 2 package or run it in extract-and-run mode:
APPIMAGE_EXTRACT_AND_RUN=1 ./Irodori*.AppImage
For release channel details and future package-manager plans, see Distribution and updates.
Headless server
Rust users who need the local HTTP API, not the desktop app, can install the
headless server from irodori-kit:
cargo install --git https://github.com/hjosugi/irodori-kit --tag v0.5.0 --locked irodori-server
See Headless local data API for runtime configuration.
Getting Started
This path gets a new user from install to a successful query without reading the architecture notes.
Install
Download the current desktop build from https://github.com/hjosugi/irodori-table/releases. The Linux build is the most actively exercised preview target.
For source builds, use the platform development guide for your OS instead of the desktop install guide: Windows, macOS, or Linux.
Create A Connection
- Open the connection manager.
- Choose a database engine.
- Enter host, port, database, user, and authentication details.
- Use the diagnostic or test action before saving.
Secrets are stored through the local OS credential store where supported. Export connection definitions without secrets when sharing project setup.
Run The First Query
- Open a SQL editor tab bound to the saved connection.
- Type a query such as
select 1;. - Run the current statement or selected text.
- Cancel from the running-query control if the statement takes too long.
The editor is local-first. SQL is inserted, formatted, or generated in the editor first; it is not sent to a database until you run it.
Read Results
Results appear in the result grid. Use copy/export for a selected range or the current page, switch result modes when available, and keep large exports bounded by using the export flow instead of copying an entire result set.
Next reads:
Connections
Connections bind editor tabs, browser metadata, result history, and diagnostics to a database source.
Daily Flow
- Create or duplicate a profile from the connection manager.
- Keep profiles organized in folders when working across projects.
- Test the profile before opening an editor tab.
- Bind a tab to the connection before running SQL.
Transport And Secrets
Profiles can use direct sockets, SSH, SOCKS/HTTP proxies, and ordered proxy chains where the engine supports them. Store reusable hops separately so several profiles can share the same transport path.
Exported connection definitions exclude secrets. Re-enter credentials after importing a profile on another machine.
Troubleshooting
Use connection diagnostics first. They separate DNS/network/proxy failures from database authentication and feature support errors. When a connector is not part of the default build, install the marketplace connector or choose an engine that is shipped in the current desktop binary.
Query Editor And Vim
The editor is the primary workspace surface. It supports multiple tabs, saved sessions, connection-bound editors, snippets, formatting hooks, and command palette actions.
Running SQL
- Run the current statement for quick iteration.
- Select text and run the selection for focused checks.
- Run the whole file when reviewing a complete script.
- Cancel long-running statements from the running-query control.
Completion
Completion uses local metadata first: schemas, tables, columns, aliases, CTEs, functions, snippets, and dialect keywords. AI assistance is optional and must be configured separately.
Vim Mode
Vim mode is meant for daily-driver editing: normal/insert/visual modes, counts, registers, marks, macros, search, and command-line style workflows. Keybindings can be remapped from settings, and conflicts should be resolved before relying on a custom map.
Results Grid And Export
The result grid is optimized for repeated inspection, copying, and export from large result sets.
Inspecting Results
- Scroll large pages without loading the entire result into memory.
- Use row details when a record is wider than the visible grid.
- Keep filters and sorting scoped to the loaded page unless a server-side workflow is explicitly available.
Copy And Export
Use copy for small selected ranges. Use export for reproducible files:
- CSV/TSV with header and delimiter controls
- JSON and NDJSON
- SQL insert/upsert scripts where supported
- Avro and Parquet for columnar workflows
Native save dialogs are used by desktop exports, including spreadsheet-friendly formats.
ERD And Schema Designer
The ERD surface is both a browser aid and a design surface.
Explore A Schema
Seed a diagram from a live connection to inspect tables, columns, primary keys, foreign keys, and relationships. Move tables to make the shape readable and keep large schemas focused on one subject area at a time.
Design Changes
Create or edit tables, columns, keys, and relationships in the designer before
generating SQL. Forward engineering emits ordered CREATE and ALTER
statements so foreign-key dependencies are applied after the base tables exist.
Exchange Diagrams
Export diagram JSON when sharing a design or keeping a review artifact with a change proposal. Import JSON to continue work later or compare a proposed design with a live connection.
Import And Migration Studio
Import/export and migration planning are separate workflows: import moves data into a table, while Migration Studio plans schema and data verification steps.
Import
Preview incoming CSV, TSV, JSON, and NDJSON data before writing it. Check inferred columns, target table names, null handling, and delimiter/quote settings before running an import.
Migration Studio
Migration Studio compares source and target metadata, builds preview SQL, and
surfaces destructive changes before execution. The reusable planning and
data-diff primitives live in irodori-migration; the desktop app supplies live
connections, jobs, cancellation, and UI review.
Verification
Use row counts, checksums, bucket fingerprints, and row-level diffs to verify a migration. For very large tables, prefer bucketed verification first and inspect only the failed buckets.
Git, Terminal, And Search
Irodori includes development-adjacent tools so SQL work can stay in one workspace.
Git Panel
Use the Git panel to inspect repository state, branches, and commits near the SQL or migration files you are editing. Commit-specific actions such as copy hash, open remote URL, and file summaries are tracked as follow-up hardening work.
Terminal
The terminal panel runs a local PTY in the desktop shell. Use it for nearby commands such as database fixtures, migration scripts, or project-local checks. Treat it like any local shell: commands run with your user permissions.
Search And Replace
Cross-tab search helps update SQL across open tabs and project buffers. Review matches before replacing, especially when connection-specific SQL dialects are mixed in one workspace.
AI Assist
AI features are optional. Deterministic completion and editor workflows work without a model or cloud provider.
Provider Setup
Configured providers share one abstraction across SQL generation and chat. Local providers can run on-device; cloud providers require user-supplied credentials stored outside the repository.
Read-Only Agent Mode
The schema-aware chat sidebar can inspect context and propose SQL. Read-only agent mode is cancellable and should not execute writes without explicit user action.
Privacy Expectations
Only enable a cloud provider when the schema or prompt content is appropriate for that provider. Keep privacy mode and redaction settings enabled when sharing logs, screenshots, or reports.
Windows Development
This guide covers local desktop development on Windows. The Tauri desktop shell should run on the Windows host because it depends on the Windows WebView2 and MSVC toolchain. WSL is useful for some Rust-only work, but it is not the primary path for desktop UI development.
Prerequisites
- Windows 10 or Windows 11 on x64.
- Git.
- Node.js 24.x, matching the repository
.nvmrc. - Rust from
rustup; the repository pins Rust 1.96.0 inrust-toolchain.toml. - Visual Studio 2022 Build Tools with the Desktop development with C++ workload, including MSVC and a Windows SDK.
- Microsoft Edge WebView2 Runtime. It is already present on most current Windows installs; install the Evergreen Runtime if Tauri reports that WebView2 is missing.
- Optional: Docker Desktop or Podman Desktop for sample database containers.
Setup
Use PowerShell or Git Bash from the irodori-table repository root:
rustup toolchain install
npm --prefix apps/desktop ci
node tools/dev/doctor.mjs
If GNU Make is available, the repository shortcuts are also supported:
make setup
make doctor
Run the desktop app
Start the Tauri development shell:
npm --prefix apps/desktop run tauri -- dev
Or, when make is available:
make desktop-dev
The development command starts Vite on http://localhost:1420 and launches the
desktop shell. Launching a debug binary directly without Vite running will show a
blank window or a connection-refused message.
Common checks
npm --prefix apps/desktop run format:check
npm --prefix apps/desktop run lint
npm --prefix apps/desktop run test
npm --prefix apps/desktop run build:verified
Use cargo test --workspace for Rust backend changes.
Sample databases
Sample database containers live in the sibling irodori-samples repository.
Clone it next to irodori-table when you need local integration fixtures:
git clone https://github.com/hjosugi/irodori-samples ../irodori-samples
Then use Docker Desktop or Podman Desktop as the container engine.
macOS Development
This guide covers local desktop development on macOS. Tauri uses the system WebKit/WKWebView stack on macOS, so no WebKitGTK packages are needed.
Prerequisites
-
macOS on Apple Silicon or Intel.
-
Xcode Command Line Tools:
xcode-select --install -
Node.js 24.x, matching the repository
.nvmrc. -
Rust from
rustup; the repository pins Rust 1.96.0 inrust-toolchain.toml. -
npm for reproducible dependency installs.
-
Optional: Docker Desktop or Podman for sample database containers.
Setup
From the irodori-table repository root:
rustup toolchain install
make setup
make doctor
The root is not an npm workspace. Prefer the root Makefile shortcuts, or run
desktop scripts with npm --prefix apps/desktop ....
Run the desktop app
make desktop-dev
make desktop-dev starts Vite on http://localhost:1420 and launches the Tauri
desktop shell. If you start a debug binary directly without Vite running, the
window will be blank or show a connection-refused message.
Common checks
make desktop-format-check
make desktop-lint
make desktop-test
make desktop-build-verified
Use cargo test --workspace for Rust backend changes.
Sample databases
Sample database containers live in the sibling irodori-samples repository:
git clone https://github.com/hjosugi/irodori-samples ../irodori-samples
make db-up DB=postgres
make db-verify DB=postgres
Use the container engine that works best on your machine. The development doctor detects Docker or Podman when either is available.
Linux Development
This guide covers local desktop development on Linux, including the common WebKitGTK dependencies and troubleshooting steps for Arch Linux, CachyOS, Debian, Ubuntu, Fedora, and similar desktop distributions.
1. System Dependencies
Required local versions are pinned in the app repository: Node.js 24.x in
.nvmrc and Rust 1.96.0 in rust-toolchain.toml.
Tauri v2 requires GTK3, WebKitGTK using the 4.1 API, libsoup3, OpenSSL,
pkg-config, and the normal app indicator/image packages used by Linux desktop
bundles. The x86_64 Linux build also uses mold because .cargo/config.toml
passes -fuse-ld=mold.
Debian / Ubuntu
sudo apt-get update
sudo apt-get install -y \
build-essential curl file libayatana-appindicator3-dev librsvg2-dev \
libssl-dev libwebkit2gtk-4.1-dev libxdo-dev mold pkg-config wget
Fedora
sudo dnf install \
gcc gcc-c++ make pkgconf-pkg-config webkit2gtk4.1-devel \
libsoup3-devel openssl-devel libxdo-devel librsvg2-devel mold
Arch Linux / CachyOS
sudo pacman -S --needed \
base-devel webkit2gtk-4.1 libsoup3 openssl pkgconf mold
After installing the OS packages, install the pinned Rust toolchain and desktop dependencies, then run the repository doctor:
rustup toolchain install
make setup
make doctor
Build temp directory
If /tmp is a small tmpfs, large Rust/Tauri builds can fail while compiling or
linking. Use a repo-local temp directory for those runs:
mkdir -p .irodori-local/tmp
TMPDIR=$PWD/.irodori-local/tmp make desktop-build-verified
AppImage FUSE Dependency
Arch Linux and CachyOS default to fuse3. To run built AppImages directly
without extracting them, you can optionally install FUSE v2:
sudo pacman -S --needed fuse2
If you do not want to install fuse2, you can execute the AppImage by
extracting it inline using the environment variable:
APPIMAGE_EXTRACT_AND_RUN=1 ./Irodori-Table.AppImage
(This is handled automatically by the project’s make run-linux and apps/desktop/tools/install-linux.mjs wrapper).
2. Troubleshooting GPU & WebKit Crashes
On Arch-based distros (especially those using NVIDIA drivers, Wayland, or Mesa hybrid graphics), the WebKit2Gtk rendering engine might crash silently or produce white screens. Use the following workarounds:
WebKit DMA-BUF Crash (White/Blank Screen)
If the application launches but renders a solid white screen or crashes with WebProcess failures in journalctl, disable DMA-BUF rendering:
export WEBKIT_DISABLE_DMABUF_RENDERER=1
Compositing Mode Crash
If the window still crashes, force software compositing:
export WEBKIT_DISABLE_COMPOSITING_MODE=1
Wayland vs. X11 Backend
If WebKit has input focus or window rendering issues under Wayland, force GDK to run via XWayland:
export GDK_BACKEND=x11
Or force Wayland native:
export GDK_BACKEND=wayland
3. Running and Debugging Locally
Running in Dev Mode
To run the hot-reloading development server:
make desktop-dev
make desktop-dev runs the Tauri CLI from apps/desktop, which starts Vite and
the desktop shell together.
Direct Binary Execution
Heads up: a debug binary loads its UI from the Vite dev server (
devUrl http://localhost:1420intauri.conf.json). Launching the debug binary on its own shows a blank window with “Could not connect to localhost: Connection refused” because nothing is serving port 1420. See the troubleshooting entry below.
To inspect Rust stdout/logs while still pointing the webview at a running UI, start the dev server first, then launch the binary in a second terminal:
# Terminal 1 - serve the frontend on :1420
make desktop-vite
# Terminal 2 - run the already-built debug binary
./.irodori-local/target/debug/irodori-table-desktop
To run a standalone binary that needs no dev server, build one with the
frontend embedded from frontendDist (../dist):
make desktop-build # populate apps/desktop/dist
npm --prefix apps/desktop run tauri -- build --debug
# Or a full AppImage with embedded assets:
make run-linux
Error: “Could not connect to localhost: Connection refused”
A blank window with this message is not a database error - the webview could
not reach the dev server URL baked into a debug build (http://localhost:1420).
Checklist:
- Use
make desktop-devinstead of launching the debug binary directly - it starts Vite (beforeDevCommand) and the app together. - If you must run the binary directly, confirm Vite is up:
ss -ltnp | grep 1420should show a listener. If not, runmake desktop-vitefirst. - The dev port is fixed and
strictPort: true, so if:1420is already taken, Vite exits and the app has nothing to connect to. Free the port (fuser -k 1420/tcp) or stop the other process, then retry. - For a no-dev-server run, use an embedded-assets build
(
npm --prefix apps/desktop run tauri -- build --debugormake run-linux); a debug binary alone always expects:1420.
Reading Console and Rust Logs
- Developer Tools: Open Help > Open Developer Tools from the app menubar during debug/dev runs. The WebView’s default right-click inspection menu is suppressed so product context menus stay clean.
- Stdout/Stderr Console: Run the app from a terminal. Console logs (
console.log) from the React frontend andprintln!/logevents from the Rust backend will print directly to the terminal stdout. - Core Dumps & Journal: If the app segfaults or WebKit crashes, inspect system logs:
journalctl -xe --user -u irodori-table # Or simply view core dump stats: coredumpctl list
Extension Development
Irodori Table treats extensions as a product surface. The extension system starts with TypeScript because that is the fastest path for commands, UI integrations, themes, result-grid tools, and SQL dialect metadata. Rust/Wasm remains available for high-performance drivers, parsers, renderers, and formatters.
Current Implementation
- Manifest schema:
extension.schema.json, for files namedirodori.extension.json. - Rust source of truth:
irodori-extension. - Generated SDK contracts:
packages/extension-sdk/src/generated/irodori-extension-api.ts. - TypeScript SDK:
packages/extension-sdk/src/index.ts. - Local dev CLI:
packages/extension-sdk/bin/irodori-extension-dev.mjs. - Templates:
packages/extension-sdk/templates/typescript-basicandpackages/extension-sdk/templates/wasm-sql-dialect. - Native connector examples:
irodori-extension-duckdbandirodori-extension-memgraph. - Native connector host:
irodori-tableincludes the dynamic-library extension host, manifest/integrity checks, and marketplace catalog plumbing. The shared native ABI helper/macro lives inirodori-connector-abi.
Manifest
Extensions declare a strict irodori.extension.json manifest. The schema rejects
unknown top-level and contribution fields so the host can safely validate packages
before loading them.
{
"$schema": "../../extension.schema.json",
"manifestVersion": 1,
"id": "example.quick-export",
"name": "Quick Export",
"version": "0.1.0",
"license": "MIT OR 0BSD",
"apiVersion": "0.1",
"runtime": "typescript",
"entry": "dist/main.js",
"permissions": ["commands", "queryResults:read", "resultRenderers"],
"contributes": {
"commands": [
{
"id": "quickExport.copyAsMarkdown",
"title": "Copy Result as Markdown Table",
"category": "Result Grid",
"enablement": "resultGridFocus"
}
],
"resultGridActions": [
{
"id": "quickExport.copyMarkdownAction",
"title": "Copy as Markdown",
"command": "quickExport.copyAsMarkdown",
"when": "resultGridFocus"
}
]
}
}
Core manifest fields:
manifestVersion: currently1.apiVersion: currently0.1.runtime:typescript,javascript,wasm, ornative.permissions: explicit capability scopes such ascommands,queryResults:read,themes,sqlDialects,native, andwasm.contributes: declarative commands, keybindings, result-grid actions/renderers, themes, and SQL dialects.capabilities: Wasm and native module declarations.dev: watch paths, fake database fixtures, and log file configuration for local development.
Validate all checked-in extension templates and examples from the repository root:
make extension-manifests
The same guard runs in CI and checks required fields, unknown keys, safe relative paths, permission/contribution consistency, template/example licenses, and manifest sample fixtures.
Type Generation
The extension SDK uses the same typeship pattern as the desktop app.
cargo test -p irodori-extension export_typescript_bindings
The Rust crate owns the serde/TS contracts for:
- manifest and contribution data;
- permission scopes and permission inspection;
- result-grid columns, rows, selections, and snapshots;
- theme definitions and token color rules;
- SQL dialect definitions, keywords, snippets, and formatter config;
- Wasm/native module capability metadata;
- local development fixtures and logs.
The generated file is committed. In CI, the same test runs in check mode and fails if the generated SDK types drift from Rust.
TypeScript SDK
The SDK exposes generated contracts plus host-facing interfaces:
commands.registerCommandandcommands.executeCommand;keybindings.registerKeybinding;resultGrid.getActiveSnapshot,resultGrid.getSelection,resultGrid.registerAction, andresultGrid.copyText;themes.registerTheme;sqlDialects.registerDialect;permissions.has,permissions.require, andpermissions.inspect;- structured extension logging.
Extensions implement:
import type { ExtensionContext } from "@irodori-table/extension-sdk";
export async function activate(context: ExtensionContext): Promise<void> {
context.subscriptions.push(
context.commands.registerCommand("example.hello", async () => {
context.log.info("hello from an extension");
}),
);
}
Local Development
The local dev CLI reads a manifest, inspects declared permissions, loads fake database fixtures, writes JSON-line logs, and watches declared files for reload requests.
node packages/extension-sdk/bin/irodori-extension-dev.mjs packages/extension-sdk/templates/typescript-basic --once
The --once mode is useful for CI and smoke checks. Without it, the command stays
running and reports reload requests when watched paths change.
Runtime Safety Rules
- Extensions must declare permissions before using privileged APIs.
- Query text, query results, schema metadata, file access, native code, and Wasm modules are sensitive.
- Secrets are never exposed directly; extension APIs should receive handles or scoped operations.
- Native modules require platform metadata and should include
sha256before marketplace distribution. - Wasm modules must declare an ABI string. Current templates use
irodori-sql-dialect-v0while the host ABI is still stabilizing.
Next Host Work
- Wire manifest validation into the desktop extension loader.
- Implement the real desktop extension host behind the SDK interfaces.
- Add package archive verification and install/uninstall flows.
- Surface logs, reload state, and permission inspection in a developer panel.
- Add runtime validation for extension-provided theme, dialect, and renderer data.
i18n
Irodori Table keeps desktop UI translations in apps/desktop/src/i18n.
Supported Locales
en- English, the fallback locale.ja- Japanese.
The language is selected from Settings -> General -> Language. The selected
locale is saved in local storage as irodori.locale.v1 and is also included in
Settings JSON as locale.
Adding Or Updating Text
- Add the English source string to
apps/desktop/src/i18n/locales/en.ts. - Add the Japanese translation to
apps/desktop/src/i18n/locales/ja.ts. - Use
createTranslator(locale)ortranslate(key, options)at the UI boundary. - Add or update unit coverage in
apps/desktop/src/tests/unit/i18n/i18n.test.ts.
English is the source of truth for message keys. Japanese is typed against the same key set, so missing translations fail during TypeScript checks instead of rendering a blank label.
Interpolated values use {name} style placeholders:
translate("settings.theme.colorMode.customDescription", {
locale: "ja",
values: { name: "Dark+" },
});
Keep translation calls near the React component boundary. Business logic, storage, and query execution code should store stable IDs or raw data, not localized display text.
Development Security
Last updated: 2026-06-26 JST.
This document covers day-to-day security controls for Irodori Table development. Release/distribution requirements live in distribution.md; clean-room and license rules live in clean-room.md and licensing.md.
Package Manager Policy
- npm lockfiles are the reproducible source of truth for JavaScript dependency resolution.
- Bun is allowed for local script execution through
JS_PM=bun, but do not commit Bun lockfiles unless the project explicitly migrates package managers. - Use
npm cifor CI-equivalent installs and before release work. - Use
make setup-fastonly as a local convenience path. - Do not run
npm audit fix --forceas a blind cleanup. Review the dependency tree and behavior changes, then update intentionally.
Supply Chain Checks
Use:
make security
The target runs:
scripts/check-licenses.sh;scripts/dependency-review.mjsfor install scripts, remote tarball integrity, non-registry npm resolution, Cargo git sources, and external Cargo path dependencies;cargo metadata --locked;npm audit --package-lock-only --audit-level highfor each npm lockfile;npm audit signatures --package-lock-onlyfor npm registry signature checks;cargo audit --deny warningswhencargo-auditis installed.
Set NPM_AUDIT_LEVEL=moderate to make npm advisory checks stricter. CI sets
REQUIRE_CARGO_AUDIT=1 so missing RustSec coverage fails the workflow.
New install scripts, Cargo git dependencies, or external Cargo path
dependencies must be reviewed and documented in
tools/security/dependency-review-allowlist.json.
Dependency Review Rules
Treat a new dependency as a design decision, not a convenience import.
Before adding one:
- prefer the standard library, existing project dependencies, or small local code when the behavior is simple;
- check license compatibility against
docs/licensing.md; - check install scripts, native binaries, generated code, postinstall downloads, package ownership, and recent maintainer churn;
- pin behavior through the existing lockfile and include the lockfile diff in the same change;
- add tests around the behavior the dependency is expected to provide.
Extra scrutiny is required for database drivers, parser/grammar packages, cryptography, compression/archive libraries, native modules, browser-executed WASM, and release/signing tools.
Secrets And Logs
- Do not persist plaintext database passwords or tokens.
- Do not commit
.envfiles, sample credentials beyond local throwaway containers, private certs, database dumps, or screenshots containing secrets. - Redact passwords, tokens, connection URLs, and certificate material before logging or surfacing errors.
- Keep import/export paths explicit and user-chosen; avoid background writes to broad directories.
GitHub Actions
- Keep workflow permissions minimal. Default to
contents: read. - Use official actions where possible and let Dependabot update action versions.
- Be cautious with new third-party actions; prefer shell commands or existing toolchains when the action is only a thin wrapper.
- Any workflow that publishes artifacts, signs releases, uploads SARIF, or uses OIDC must declare the narrow permissions it needs.
Current security workflows:
Security: dependency policy, npm advisory/signature checks, and RustSec.CodeQL: static analysis for JavaScript/TypeScript and Rust.OpenSSF Scorecard: repository supply-chain posture surfaced through code scanning SARIF. Public score publishing is disabled.
Release Hardening Backlog
These are intentionally not solved by the current local checks:
- sign desktop artifacts and document verification;
- generate SBOMs for release artifacts;
- pin container base images by digest once the release cadence is stable;
- add secret scanning/push protection in the hosted repository settings;
- evaluate SLSA provenance for release builds.
Repository Settings Checklist
These are configured in GitHub settings rather than committed files:
- enable Dependabot alerts and security updates;
- enable secret scanning and push protection;
- require
Security,CodeQL, and normal CI checks before merging tomain; - protect release tags once signed releases are introduced;
- restrict who can approve and run workflows from external pull requests.
Reference And License Policy
Irodori Table’s own code is MIT OR 0BSD: downstream users should be able to choose familiar MIT terms or the almost-no-conditions 0BSD path. Reference rules still depend on license and source type. Proprietary products require clean-room treatment. OSS projects may be studied at code level when their license permits it, but copied or adapted code must keep attribution and must be compatible with Irodori Table’s permissive core.
Allowed
- Read public documentation, public issue trackers, release notes, product pages, and license files.
- Read code from OSS repositories after checking the relevant license.
- Adapt small, well-scoped OSS implementation ideas only when the license is compatible with a permissive
MIT OR 0BSDproject, attribution is preserved where required, and the copied/adapted boundary is explicit in the commit. - Use installed apps manually to understand workflows and expected DB-client behavior.
- Record feature-level observations in our own words.
- Build independent prototypes from requirements, public standards, database documentation, and permissively licensed dependencies.
- Compare behavior after our implementation exists, at the level of user-visible outcomes.
Not Allowed
- Copy proprietary or license-incompatible source code, private APIs, icons, images, theme files, distinctive UI wording, snippets, or exact layout measurements from reference clients.
- Translate proprietary or license-incompatible code into Rust, TypeScript, or another language.
- Recreate a competitor screen pixel-for-pixel.
- Use decompiled binaries, network traces, private builds, paid-only assets, or non-public materials.
- Paste third-party code into issues, docs, prompts, commits, or tests unless its license is verified and the source is attributed.
- Use code under commercial-only directories or dual-license sections unless the license explicitly permits our use.
Reference Tiers
- Proprietary or unclear license: public behavior and docs only; clean-room implementation.
- Public-domain-like or no-attribution permissive OSS such as 0BSD/Unlicense/CC0: easiest to reuse, while still recording provenance.
- Permissive OSS such as MIT/Apache/BSD: code may be read and selectively adapted with attribution and dependency/license tracking.
- Copyleft OSS such as GPL/AGPL: code may be read for learning; do not copy/adapt into the permissive core without an explicit separate license boundary and compatibility review.
- Commercial/paid edition source: do not use unless we have explicit rights.
Named Reference Licenses
Verify the local LICENSE before any code-level use; this table records the current understanding.
.irodori-local/ref/beekeeper-studio-master/— Community Edition GPLv3-or-later (copyleft);src-commercialis separately licensed and off-limits. Learning only; no copy into the permissive core..irodori-local/ref/vscode-sqltools-dev/— MIT. Code may be read and selectively adapted with attribution and license tracking..irodori-local/ref/vscode-mssql-main/— MIT. Same as above..irodori-local/ref/budibase-master/— verify before code-level adaptation (GPL/AGPL components exist); treat as behavior reference unless a specific file’s license is confirmed compatible..irodori-local/ref/duckdb-ui-main/— MIT. Permissive; adaptable with attribution..irodori-local/ref/kibana-main/— Elastic License 2.0 / SSPL / AGPL-3.0 (source-available, restrictive/copyleft). Behavior-only; no code adaptation into the core.zed-industries/zed(GitHub, not vendored) — GPL-3.0/AGPL-3.0 with some Apache-2.0 crates (copyleft). Study architecture; do not copy copyleft code into theMIT OR 0BSDcore.- A5:SQL Mk-2 (
a5m2.mmatsubara.com, not vendored) — freeware with private source repository. Public site / behavior reference only. Capture useful feature observations indocs/reference-a5sql.md; do not copy UI expression or private implementation into theMIT OR 0BSDcore. outerbase/studio(GitHub, not vendored) — AGPL-3.0 (copyleft). Study the data-editor/schema-editor/large-table UX and architecture; do not copy code into theMIT OR 0BSDcore..irodori-local/ref/dbeaver-ce(DBeaver Community) — Apache-2.0 (permissive). Code may be read and selectively adapted with attribution and NOTICE retention; avoid the 2 EPL-2.0 files (HippieCompletionEngine.java,SQLMatchingCharacterPainter.java) unless accepting EPL terms.zequel-labs/zequel(GitHub, not vendored) — Elastic License 2.0 (source-available, restrictive). Behavior-only; no code into the core.rust-dd/rsql(GitHub, not vendored) — README says open source and links aLICENSE, but that path returned 404 during review. Treat as public README/behavior reference only until compatible license terms are verified. Capture performance and UX observations indocs/reference-rsql.md; do not copy code into theMIT OR 0BSDcore.
Reference Workflow
- Check the license before opening code for implementation guidance.
- Capture feature observations in a neutral matrix: what the workflow does, why users need it, and how important it is.
- Prefer public specifications and vendor docs for implementation details: SQL dialect docs, driver docs, SSH/proxy standards, LSP, Tree-sitter, VS Code theme schema.
- Implement from our own abstractions and tests unless the OSS license explicitly permits adaptation and the PR records that fact.
- Review pull requests for accidental copied strings, asset reuse, incompatible code, and too-close UI expression.
- Keep third-party dependencies explicit with license review before shipping.
Contribution Checklist
- The change is written from project requirements or from license-compatible OSS with required attribution.
- Any third-party dependency has a compatible license.
- Public references are linked when a behavior is based on public docs.
- OSS code references are linked when implementation is influenced by code-level review.
- User-visible names, empty states, dialogs, and shortcuts are ours unless they are generic platform conventions.
- Tests assert Irodori behavior, not another product’s private behavior.
Completion And AI Strategy
Last checked: 2026-06-26 JST.
AI can make Irodori nicer, but it must not be required for a great query editor. The base product should feel nearly perfect with no network, no model, and no external account.
Current product status: the desktop editor now has deterministic schema/table/column autocomplete from live metadata, with unit coverage for the local completion engine and browser E2E coverage for CodeMirror popup suggestions. The remaining cross-platform product requirement is the shared serializable completion request/response contract for local API and future hosts, plus broader engine fixtures beyond the desktop smoke.
Layering rule:
- Deterministic completion is the core editor contract. It runs locally, works offline, uses structured metadata, and must be good enough before any AI path matters.
- Optional AI is an overlay. It can explain, draft, repair, or propose text/diffs, but it is off by default, permission-scoped, and must never replace or block deterministic completion.
- ML infrastructure is required even though user-facing AI is optional. Ranking experiments, provider/model evaluation, local dataset preparation, and quality regression checks must run through the same background job and privacy model as huge index builds and other batch work.
Deterministic Completion First
The completion engine should be built from structured local knowledge. SQL is the first target, but the design must also cover Cypher, time-series SQL/native queries, document queries, key-value commands, search DSLs, and warehouse dialects.
- Incremental SQL parse context from Tree-sitter or dialect-specific parsers.
- Dialect metadata for keywords, functions, operators, DDL/DML syntax, bind variables, comments, quoting rules, and procedural SQL.
- Metadata cache populated by introspection, including schemas, tables, views, columns, indexes, constraints, foreign keys, functions, procedures, packages, triggers, sequences, enum-like values, comments, and privileges.
- Scope resolver for aliases, CTEs, recursive CTEs, derived tables, subqueries, lateral joins, temp tables, table-valued functions, window definitions, and DDL files.
- Query-local symbols from the current editor, unsaved scratch buffers, selected connection, active schema, and tab/session binding.
- Ranking from current context, foreign-key paths, recently used objects, pinned/favorite objects, history, cursor position, and statement type.
Completion categories:
- Keywords and syntax snippets.
- Database, schema, table, view, column, alias, CTE, and subquery output names.
- Function/procedure/package signatures, named parameters, overloads, and return types.
- Join suggestions from foreign keys and naming conventions.
- Insert/update column lists, generated select lists, and group-by/order-by helpers.
- Query parameters and local variables.
- File paths, connection names, tab/session names, and run configurations.
- Dialect-specific explain, analyze, transaction, and administrative commands.
- Graph labels, relationship types, property keys, path patterns, Cypher procedures/functions, and graph result variables.
- Time-series buckets/measurements/tables, tags, fields, time columns, retention policies, aggregate/window helpers, downsampling snippets, and time-range templates.
- Document/KV/search names such as collections, indexes, keys, commands, aggregation stages, JSON paths, search fields, and module-specific functions.
Quality bars:
- No false confidence: prefer fewer precise suggestions over noisy lists.
- Suggestions must be cancellable, fast, and stable while metadata refreshes in the background.
- Completion must work offline and without AI.
- Completion must never leak result data or secrets to an external provider.
- Large metadata/search indexes must build incrementally in background jobs with progress, cancellation, checkpoint/resume, bounded memory, and measurable throughput.
ML And Batch Requirements
ML is a product-quality requirement for ranking, evaluation, and optional assistant quality, but it must not turn the editor into a network-dependent product.
- Dataset generation uses only permitted local artifacts: dialect facts, source snapshots, schema metadata, query history, selected editor context, execution errors, and opt-in result samples.
- Evaluation runs are versioned jobs with reproducible inputs, model/provider metadata, quality metrics, latency/cost metrics, and artifact hashes.
- Huge index builds, embedding/vector indexes, metadata indexes, and source-search indexes are cancellable, checkpointed, and disk-backed where needed.
- Batch work uses the shared job model so desktop, local API, and future hosts can inspect progress, cancel work, resume where safe, and collect logs/artifacts consistently.
- External provider calls are forbidden unless workspace policy explicitly permits the specific data classes used by that run.
Optional AI Layer
AI should sit above the deterministic engine as an opt-in assistant. The items below are target capabilities, not a claim that the product ships them today:
- Natural-language-to-SQL generation.
- Inline SQL ghost text and patch-style suggestions, only when enabled.
- AI Shell (open work): a dockable chat panel scoped to the current connection/workspace.
- Query/error explanation and suggested fixes.
- Explain-plan summary.
- Schema-aware chat.
- Refactor SQL, format intent, or generate migration draft.
- Test data or sample query generation.
Provider model:
- Local providers: Ollama or other local OpenAI-compatible endpoints.
- Cloud providers: OpenAI-compatible, Anthropic, Gemini, Azure OpenAI, Amazon Bedrock, and similar via extension providers.
- MCP/Copilot-compatible bridge: expose Irodori context through scoped local tools so supported clients can request schema/query context where allowed; do not share database credentials, result samples, or query text unless the workspace policy explicitly permits that class of data.
Privacy rules:
- AI is off by default.
- The user must opt in per provider and per workspace.
- Schema metadata, query text, result samples, and execution plans are separate permissions.
- Result data is never sent unless the user explicitly allows it for the current action.
- Redaction should run before provider calls.
- Every AI request should be inspectable in an audit panel.
Execution boundary:
- AI suggestions are text until the user inserts them into the editor.
- The AI Shell cannot run SQL directly; it can only populate the editor or call explicitly scoped read-only tools.
- Query Magics are not AI. The desktop baseline is local, explicit, line-leading commands such as
\describe,\explain,\export,\erd, and\params; command-palette equivalents, structured action audit/history, and run-to-file magic remain open.
Copilot Compatibility Direction
Directly embedding GitHub Copilot inside a standalone app may not be available as a stable public integration path. The safer first target is a cross-platform Irodori MCP server plus optional editor/provider extensions. The same scoped tool contracts should serve desktop, the local API, and future hosts instead of creating a desktop-only Copilot path.
Milestones:
irodori-mcp: expose safe tools for schema search, object details, explain-plan fetch, scoped read-only query execution, SQL history search, and SQL diagnostics.- Shared context envelope: separate selected SQL, cursor context, schema metadata, execution plans, result samples, and history snippets so policy can allow or deny each class independently.
- Copilot-style inline autocomplete: provide opt-in text/diff suggestions from selected SQL, cursor context, and permissioned schema metadata; never execute suggestions automatically.
- VS Code config generator: create
.vscode/mcp.jsonfor connecting Copilot Chat to a local Irodori MCP server. - Extension SDK provider API: allow third-party AI providers and Copilot-style bridges without hard-coding a vendor into core.
- Policy controls: disable external AI, allow only local models, allow only schema metadata, or allow result samples per workspace.
Sources:
- https://docs.github.com/en/copilot/concepts/context/mcp
- https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp-in-your-ide/extend-copilot-chat-with-mcp
- https://docs.snowflake.com/en/user-guide/snowflake-copilot-inline
- https://www.jetbrains.com/help/datagrip/ai-assistant.html
Research Notes
- JetBrains’ full-line completion work is relevant because it emphasizes local, latency-aware, syntax-safe suggestions rather than pure cloud generation.
- The Mellum work is relevant because it focuses on compact, IDE-oriented completion models with context packing and permissively licensed training data.
- Control/gating models are relevant because AI completion should trigger only when useful, reducing noise, cost, and privacy exposure.
Sources:
- https://arxiv.org/abs/2405.08704
- https://arxiv.org/abs/2510.05788
- https://arxiv.org/abs/2601.20223
Data Verification And Migration
Last checked: 2026-06-28 JST.
This page records the current product contract for migration planning, data verification, and result-grid repair helpers. It separates what is implemented today from the target live diff architecture.
Current Desktop Scope
The desktop app currently ships SQL generation and review workflows, not an end-to-end data mover.
- Migration Studio generates a plan, source SQL, target SQL, diff SQL, and a runbook.
- The default migration shape is Hive -> Snowflake.
- Planner engines include Hive, Snowflake, PostgreSQL, Oracle, MySQL/MariaDB, Redshift, Databricks/Spark SQL, Trino/Presto, DuckDB/DuckDB-Wasm, Apache Iceberg REST, and AWS S3 Tables.
- Generated validation SQL uses source and target row-hash manifests, row count, key count, min/max hash fingerprints, manifest tables, and row-level diff SQL.
- The desktop planner exposes Parquet/CSV extraction formats. The shared
irodori-sqlmigration helpers also include TSV-oriented load snippets for workflows where Hive text exports are unavoidable. - DuckDB/Iceberg paths generate
INSTALL/LOAD iceberg,CREATE SECRET, andATTACH ... TYPE ICEBERGpatterns for local or browser-side DuckDB compute.
The current planner does not connect to both databases, execute the generated SQL, or reconcile results by itself. The user reviews the SQL/runbook and runs it through the normal query workflow or an external migration runner.
Result-Grid Repair Workflow
Editable results are intentionally review-oriented.
- The grid uses Save Changes for pending edits.
- Editable updates require a direct single-table result with a visible primary key or unique key.
- Refresh with unsaved result changes asks for confirmation before discarding work.
- Row SQL turns the selected result row into a reviewable transaction:
-- Generated from the selected result row. Review before running.
-- Edit the SET values, then run this transaction.
BEGIN;
UPDATE "schema"."table"
SET
"column" = 'new value'
WHERE
"id" = 42
;
COMMIT;
SQL Server uses BEGIN TRANSACTION; and bracket identifiers; MySQL/MariaDB/TiDB
use backticks. JSON-like result values are serialized as SQL string literals
before insertion into the editor. The generated SQL is never executed
automatically.
Editor Support
The SQL editor is CodeMirror 6 based. Current editor behavior includes:
- dialect-aware highlighting and completion;
- Vim mode;
- format and comment toggle commands;
- run current, run selection, and run all flows;
- query history;
- search and replace through the CodeMirror search panel opened by
Ctrl/Cmd+F.
Target Live Diff Architecture
The future live data-diff capability should be a separate execution boundary. It should compare two sources without pulling whole tables unless the cheap gates fail.
The target tiers are:
- Count and table fingerprint: row count plus order-independent aggregate of row hashes.
- Partition or hash-bucket fingerprint: localize mismatches to small key ranges.
- Failed-bucket row diff: compare
(key, row_hash)manifests and fetch full rows only for changed keys.
For 100B-row scale, the product contract is to push hashing and bucketing into the source engines, stream narrow manifests, spill to disk when needed, and keep the UI cancellable. The UI should present summary status, bucket heatmap, row list, cell-level differences, and exportable evidence.
Not Yet Implemented
- Live source-target execution and reconciliation.
- Recursive bucket localization.
- Bucket heatmap UI.
- Headless
/v1/diffAPI. - Automatic reconciliation script export beyond selected-row
UPDATEgeneration.
Safety Rules
- Keep migration credentials in connection profiles or secret storage, not in shareable URLs or exported runbooks.
- For DuckDB-Wasm and Iceberg REST, verify endpoint reachability and CORS before relying on a browser-only flow.
- Prefer Parquet for Hive -> Snowflake. Use text formats only when unavoidable, and keep delimiter/null-token policies explicit.
- Keep generated Row SQL in the editor for human review before execution.
Data Source Coverage Strategy
Last checked: 2026-06-21 JST.
Irodori Table should become a general high-performance database workbench, not only a SQL table browser. SQL databases stay the first vertical slice, but the architecture must allow distributed SQL, time-series, graph, document, key-value, search, warehouse, and local embedded sources.
Direction
The core abstraction should be data source adapter, not just SQL driver.
Each adapter declares:
- connection profile schema;
- transport needs, including direct, TLS, SSH, SOCKS/HTTP, and proxy chains;
- query language and parser strategy;
- introspection model;
- result shapes: table, document, graph, time-series frame, key-value set, stream, or binary/file;
- editable operations and safety rules;
- completion providers;
- explain/profile support;
- import/export capabilities.
The UI should keep one familiar workbench while changing the specialized panes per source type. Snowsight-style parity gaps must be designed as shared product capabilities, not as desktop-only widgets: schema-aware autocomplete, optional Copilot-style inline help/MCP, explain/query profile, advanced filters, inline editing, query-result graph views, and charts/dashboards need reusable contracts that desktop, local API, and future hosts can share.
Coverage Tiers
P0: First Usable Core
- SQLite
- PostgreSQL
These prove connection management, editor execution, object browser, result grid, history, keybindings, themes, and command palette.
P1: Daily Driver SQL And Enterprise
- MySQL/MariaDB
- SQL Server
- Oracle Database
- DuckDB
This tier stays focused on daily-driver relational workflows and enterprise SQL coverage. DuckDB is included early because it doubles as a local analytics engine and lakehouse execution option. Wire-compatible or partially landed adapters can exist before this tier is complete, but first-class source UX remains tracked by the backlog ticket for each source.
Oracle is a roadmap non-negotiable, so its connection story must be as easy as the rest. The target is a thin driver: a pure-Rust implementation of the Oracle Net/TNS protocol that needs no Oracle Instant Client — the same approach that makes A5:SQL Mk-2’s “direct connection” mode (and the JDBC Thin / python-oracledb thin / node-oracledb thin drivers) client-free. The user supplies a connection descriptor (host/port/service), not a tnsnames.ora plus a client install.
- Primary path: inherit and harden the permissively licensed
oracle-rscrate (MIT/Apache-2.0, pure Rust, Tokio, TLS/Wallet) rather than writing the TNS stack from scratch. It is young (v0.1; many enterprise features still “planned”), so a spike (SRC-004a) must validate it against real Oracle 19c/23ai before Oracle becomes first-class. This may grow into its own crate/sub-project, liketypeship. - Clean-room note: A5:SQL Mk-2 is closed source (the author’s GitHub confirms it is not public) and its direct mode uses the commercial UniDAC component, so we study the approach (thin TNS), never A5/UniDAC code.
oracle-rsis permissive and may be adapted with attribution. - Optional fallback: thick OCI via the ODPI-C
oraclecrate behind a build feature, for environments that already have the Instant Client and need full OCI features.
P2: Broader Modern Workloads
- InfluxDB and other time-series engines
- Neo4j and graph databases
- YugabyteDB YSQL
- CockroachDB
- Cassandra/ScyllaDB and wide-column stores
- ClickHouse
- BigQuery
- Snowflake
- Redshift
- Trino/Presto
- Firebird
- Elasticsearch/OpenSearch
- Couchbase
- DynamoDB
- TiDB
- Databricks/Spark SQL
- Apache Hive
- Apache IoTDB
- QuestDB
- TimescaleDB
- ArangoDB
- Memgraph
- Redis
- MongoDB
YugabyteDB should start through its PostgreSQL-compatible YSQL surface, then add distributed-database affordances such as tablets, regions, follower reads, query diagnostics, xCluster, and node/session visibility where public APIs allow it.
MongoDB, Redis, Cassandra, CockroachDB, ClickHouse, BigQuery, Snowflake, and wire-compatible engines may have landed adapter pieces before the full source experience is done. Treat those as implementation progress snapshots, not completion of native browsing, editing, completion, explain/profile, visualization, or cross-platform contracts.
Priority Within P2: Lakehouse And Cloud Warehouse Auth
- Apache Iceberg is the priority lakehouse target. Reach it through catalogs — Hive Metastore, AWS Glue, REST, and JDBC — and through AWS S3 Tables. Treat object stores (S3, GCS, Azure Blob) as first-class connection backends.
- Execution options: embeddable engines (DuckDB, Apache DataFusion) for local reads, or Trino/Presto and warehouse-native engines for pushdown. Current Migration Studio generates DuckDB/DuckDB-Wasm + Iceberg REST/S3 Tables attach patterns; live execution and catalog browsing are still future work. Add Delta Lake and Apache Hudi after Iceberg.
- Snowflake needs full authentication coverage, not just password: key-pair (JWT), OAuth, external-browser/SSO, MFA/passcode, and programmatic access tokens, with warehouse/role/database context switching.
- Apache Hive stays in scope mainly as a catalog/metastore source for Iceberg and legacy warehouses.
- Elasticsearch/OpenSearch are the first search sources. Treat them as a deep source family, not a thin REST endpoint, because current general DB clients are weak here. Study Kibana Discover and Dev Tools console for behavior: data views, index/data-stream browsing, mappings and field capabilities, filter/query composition, saved searches, request history, explain/profile, shard/index health cues, and JSON/ES|QL-style authoring. Kibana is a behavior-only reference because it is source-available under Elastic License 2.0 / SSPL / AGPL.
Managed Wire-Compatible Targets
Some hosted services should be supported as connection templates over existing adapters instead of adding duplicate engine variants:
- Supabase Postgres routes through the PostgreSQL adapter. Product work is around direct vs. pooler connection strings, SSL, RLS-aware docs, hosted extension discoverability, and connection-limit guidance.
- Amazon Aurora routes through PostgreSQL or MySQL depending on cluster engine. Product work is around writer/reader/custom endpoint guidance, IAM auth, cluster topology, serverless scaling context, and AWS Performance Insights links.
- Google Cloud SQL routes through PostgreSQL, MySQL, or SQL Server. Product work is around public/private IP, Cloud SQL Auth Proxy, IAM database auth, SSL certs, and instance metadata.
Shared Visual Model, Heavy Consoles Later
- P1 shared query-result graph, chart, worksheet visualization, and dashboard definition model (open; not implemented). Plan the serializable model/API early enough to shape result frames, filters, saved queries, exports, and extension visualizers across desktop, local API, and future hosts.
- Advanced ERD analysis/authoring beyond the current schema ERD baseline.
- Full graph exploration workspace beyond query-result graph visualization.
- BI-dashboard polish beyond the shared result-to-visualization model.
- Long-running monitoring consoles.
- Admin dashboards for every distributed engine.
These are valuable, but they should not delay the editor, completion, result handling, connection, proxy, source-adapter, and extension foundations. The visual/dashboard model is early product architecture; heavy managed/admin console coverage is later product depth.
Source-Type UI Requirements
Relational And Distributed SQL
- SQL editor with dialect-aware completion. Desktop schema/table/column completion is wired from live metadata; shared completion service/API parity and broader per-engine fixtures remain a P0 cross-platform gap.
- Object browser for databases, schemas, tables, views, indexes, constraints, routines, triggers, packages, extensions, and jobs.
- Result grid with streaming, cancellation, copy/export, safe editing, advanced filters, and explain/profile. Current desktop editing uses Save Changes for direct single-table results with visible primary/unique keys, plus Row SQL generation for selected-row review. Advanced filters and explain/query profile remain open P1 work.
- Distributed SQL add-ons: regions, replicas, shards/tablets/ranges, session/lock insight, follower reads, consistency notes, and topology-aware warnings.
Time-Series
- SQL or native query editor, depending on the engine.
- Time range picker bound to query templates without forcing dashboard-first UX.
- Result table plus time-series frame model.
- Fast downsampling/preview for huge ranges.
- Retention policy, bucket/measurement/table, tag/field, and partition browser.
- Query helpers for windows, aggregates, selectors, gap filling, derivative/difference, and calendar-aware grouping.
InfluxDB 3 should be treated as a first-class time-series source with SQL support, not as a generic PostgreSQL clone.
Graph
- Cypher or native graph query editor.
- Schema/introspection for labels, relationship types, properties, constraints, indexes, procedures, and functions.
- Results can be table, graph, path, scalar, or mixed records.
- Graph visualization starts with query-result graph rendering; full graph workspace features can come later.
- Completion must understand labels, relationship types, variables, path patterns, procedures, and property keys.
Neo4j should be the first graph benchmark because Neo4j Browser defines a common developer expectation: write Cypher, run queries, view tabular results, and visualize node/relationship results.
Document, KV, And Search
- Query/editor surface for native syntax and JSON-like pipelines.
- Collection/keyspace/index browser.
- Document viewer/editor with patch preview.
- Safe bulk edit flow and export.
- Completion for fields, operators, aggregation stages, commands, and index names.
Research Targets
Track both database-specific tools and broad clients:
- TablePlus, A5:SQL Mk-2, DataGrip, DBeaver, DbVisualizer, Beekeeper Studio, DbGate, SQLTools, VS Code MSSQL, pgAdmin, MySQL Workbench, Oracle SQL Developer, SSMS, HeidiSQL, SQuirreL SQL, OmniDB, PopSQL.
- MongoDB Compass, Studio 3T, RedisInsight, Neo4j Browser, Neo4j Workspace/Query, InfluxDB UI/Data Explorer, ArangoDB Web UI, Couchbase Capella UI, Cassandra/ScyllaDB tools, Grafana data-source workflows.
Use these products to identify expected behavior, not to copy protected expression.
Official Sources To Track
- YugabyteDB docs and release notes: https://docs.yugabyte.com/
- YugabyteDB YSQL API: https://docs.yugabyte.com/stable/api/ysql/
- InfluxDB 3 SQL docs: https://docs.influxdata.com/influxdb3/core/query-data/sql/
- InfluxDB 3 client libraries: https://docs.influxdata.com/influxdb3/core/reference/client-libraries/v3/
- Neo4j Browser docs: https://neo4j.com/docs/browser/
- Neo4j Cypher docs: https://neo4j.com/docs/cypher-manual/current/
- DBeaver supported database list: https://dbeaver.com/databases/
- DataGrip feature reference: https://www.jetbrains.com/datagrip/features/
- Apache Iceberg spec and REST catalog: https://iceberg.apache.org/spec/ and https://iceberg.apache.org/rest-catalog-spec/
- AWS S3 Tables (managed Iceberg): https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables.html
- Snowflake authentication options: https://docs.snowflake.com/en/user-guide/admin-security-fed-auth-overview and https://docs.snowflake.com/en/user-guide/key-pair-auth
- DuckDB SQL and extensions (incl. Iceberg/Parquet): https://duckdb.org/docs/
Add these to knowledge/sources.json so future implementation and bug fixes can query a local snapshot.
Design Guardrails
- Do not force non-SQL data into a fake relational model.
- Do not make graph and time-series support depend on dashboard/visualization features.
- Keep every source keyboard-first: editor, command palette, object browser, result focus, history, and quick open.
- Make adapters extension-friendly so uncommon databases do not require core releases forever.
- Keep protocol and driver choices swappable; some sources will use native Rust clients, some JDBC/ODBC bridges, some HTTP APIs, and some official CLIs or cloud APIs.
- Preserve the same security model across all sources: keychain secrets, proxy chains, TLS, privacy mode, audit-friendly logs, and permission-scoped extensions.
Implementation Architecture
This document explains the implementation shape of the
irodori-table repository. It is
intentionally practical: use it to decide which directory owns a change, how
frontend code reaches Rust, and where shared logic should live.
Goals
- Keep the desktop app as the product integration point.
- Keep Rust/TypeScript command payloads generated from Rust definitions.
- Keep shared crates small and earned by stable boundaries.
- Keep database execution, streaming, cancellation, and result paging in Rust.
- Keep UI workflow, layout, and interaction state in the desktop frontend.
- Keep extension contracts separate from app-only implementation details.
System View
flowchart LR
user["User"]
desktop["Desktop app<br/>apps/desktop"]
frontend["React + TypeScript UI<br/>apps/desktop/src"]
tauri["Tauri command bridge<br/>apps/desktop/src-tauri/src"]
db["DB runtime<br/>src-tauri/src/db"]
adapters["Engine adapters<br/>postgres mysql sqlite mssql duck etc."]
crates["Shared Rust crates<br/>../irodori-kit/irodori-*"]
sdk["Extension SDK<br/>../irodori-kit/packages/extension-sdk"]
samples["Sample DBs<br/>../irodori-samples/*"]
external["External foundations<br/>irodori-sql typeship irodori-knowledge"]
user --> desktop
desktop --> frontend
frontend -->|"generated irodori-api.ts"| tauri
tauri --> db
db --> adapters
db --> crates
adapters --> samples
crates --> external
tauri --> sdk
Repository Ownership
| Path | Owns |
|---|---|
apps/desktop/src/ | React UI, workbench layout, commands, settings, editor/result interactions, client stores. |
apps/desktop/src-tauri/src/ | Tauri command handlers, database sessions, Git, terminal, local AI, security state, background jobs. |
../irodori-kit/irodori-connection/ | Portable connection profile model. |
../irodori-kit/irodori-security/ | Security/audit-facing shared model. |
../irodori-kit/irodori-core/ | Shared core model and composition around connection/security/job foundations. |
../irodori-kit/irodori-completion/ | Metadata-driven completion and inspection logic. |
../irodori-kit/irodori-connector-abi/ | Native connector ABI helpers and export macro. |
../irodori-kit/irodori-generate/ | Local SQL generation planning, schema projection, runtime, verification. |
../irodori-kit/irodori-extension/ | Rust definitions for extension API generation. |
../irodori-kit/irodori-io/ | Import/export encoders and tabular data helpers. |
../irodori-kit/irodori-proxy/ | Direct/SSH/proxy transport planning and forwarding. |
../irodori-kit/irodori-secure-store/ | OS secret store integration boundary. |
../irodori-kit/irodori-server/ | Optional local HTTP API/headless surface. |
../irodori-kit/packages/extension-sdk/ | TypeScript SDK and templates for extension authors. |
tools/ | Code generation, docs checks, extension validation, security checks. |
../irodori-samples/ | Sibling checkout with database fixtures and compose files for manual and integration testing. |
Frontend Shape
The frontend is feature-first. Cross-feature composition happens in
apps/desktop/src/app/AppWorkbench.tsx, while feature behavior should stay in
apps/desktop/src/features/*.
flowchart TB
app["AppWorkbench<br/>composition and command wiring"]
shell["WorkbenchShell<br/>chrome, menu, status bar"]
stores["Zustand stores<br/>workbench/results/preferences/connections"]
editor["query-editor<br/>CodeMirror, selection, params, magics"]
results["results<br/>grid, WebGL, chart, BI, row detail, export"]
connections["connections<br/>profiles, import/export, validation"]
sidebars["workbench views<br/>Sidebar, Inspector, Git, history, completion"]
dialogs["dialogs<br/>settings, ERD, migration, import, AI"]
api["generated API<br/>src/generated/irodori-api.ts"]
app --> shell
app --> stores
app --> editor
app --> results
app --> connections
app --> sidebars
app --> dialogs
editor --> api
results --> api
connections --> api
dialogs --> api
Frontend rules of thumb:
- Put user workflow code under the owning
features/<area>/directory. - Keep reusable pure SQL helpers under
src/sql/. - Keep global keyboard metadata in
src/core/keybindings.ts. - Keep command orchestration in
features/workbench/command-handlers.ts. - Keep large repeated UI surfaces under feature
components/. - Keep cross-feature UI primitives under
src/components/— currentlyDialogShell(shared modal chrome) andErrorBoundary. - All modals render through
DialogShell: it owns the scrim overlay, ESC-to-close, click-outside, focus trap, focus restoration, androle="dialog"/aria-modal. Do not hand-roll modal overlays. - Wrap fallible subtrees in
ErrorBoundaryso a render error degrades locally instead of white-screening the whole app (the root is wrapped inApp.tsx). - Pull cohesive workbench command/state orchestration out of the
AppWorkbenchshell into kebab-case controller hooks underapps/desktop/src/app/controllers/, such asuse-editor-commands.ts,use-result-export.ts, anduse-workspace-actions.ts. - Keep
apps/desktop/src/app/hooks/for UI-local extracted hooks whose naming already follows the older camelCase pattern, such as result-grid scroll, filtering, and selection helpers. New cross-feature orchestration should usecontrollers/; new UI-local hooks should stay near the UI surface or inhooks/when they are shared insidesrc/app. - Split multi-tab dialogs into one component per tab (e.g.
features/settings/tabs/); the dialog file stays a thin shell. - Use the design tokens in
styles/base.cssfor spacing, radius, and elevation (--space-*,--radius-*,--elevation-*) instead of ad-hoc px, and theme color tokens instead of hardcoded colors. - Add or change Tauri payloads in Rust first, then regenerate TypeScript.
Backend Shape
Tauri owns local privileged work. The frontend should not know driver details, secret storage details, or streaming/paging internals.
flowchart TB
lib["src-tauri/src/lib.rs<br/>Tauri builder and command registration"]
state["Managed state<br/>DbState JobState SecurityState AiState PtyState"]
dbmod["db module<br/>commands, connection, query, stream, spill, meta, edit"]
engine["engine adapters<br/>postgres mysql sqlite mssql duck snowflake ..."]
git["git module<br/>status, log, diff, branch, push/pull"]
pty["pty module<br/>integrated terminal sessions"]
jobs["jobs module<br/>desktop job commands"]
ai["ai module<br/>local generation state"]
security["security module<br/>audit and redaction state"]
crates["shared crates<br/>completion proxy io generate server"]
lib --> state
lib --> dbmod
lib --> git
lib --> pty
lib --> jobs
lib --> ai
lib --> security
dbmod --> engine
dbmod --> crates
ai --> crates
jobs --> crates
Backend rules of thumb:
- Add a Tauri command only when the UI needs a privileged/local boundary.
- Keep per-engine driver logic in
src-tauri/src/db/<engine>.rs. - Keep engine-independent query splitting, result shaping, streaming, and spill
behavior in
db/query.rs,db/stream.rs, anddb/spill.rs. - Keep metadata conversion in
db/meta.rs. - Keep connection profile normalization and redaction in
db/profile.rs. - Keep generated command DTOs serializable with
serde(rename_all = "camelCase")andts-rswhere they cross to TypeScript.
Command And Type Boundary
Rust is the source of truth for desktop command payloads. TypeScript consumes generated bindings rather than hand-writing copies.
flowchart LR
rust["Rust structs/enums<br/>serde + ts-rs"]
tests["cargo test export_typescript_bindings"]
generated["apps/desktop/src/generated/irodori-api.ts"]
ui["React features"]
extRust["../irodori-kit/irodori-extension"]
extGenerated["../irodori-kit/packages/extension-sdk/src/generated"]
sdk["../irodori-kit/packages/extension-sdk"]
check["typegen drift check<br/>npm run typegen:check"]
rust --> tests --> generated --> ui
extRust --> tests --> extGenerated --> sdk
generated --> check
extGenerated --> check
Use these commands:
make desktop-typegen
make desktop-typegen-check
make desktop-build-verified
Query Execution Flow
The query path is intentionally Rust-heavy so large result sets, cancellation, and disk offload stay bounded.
sequenceDiagram
participant Editor as QueryEditorPane
participant App as AppWorkbench
participant API as generated irodori-api.ts
participant Tauri as Tauri command
participant DB as DbState / db module
participant Conn as Connection trait
participant Grid as ResultsPane
Editor->>App: run current / selection / all
App->>API: dbRunQueryStream or dbRunQuerySpill
API->>Tauri: invoke command
Tauri->>DB: validate profile, query, limits
DB->>Conn: execute through engine adapter
Conn-->>DB: rows, metadata, elapsed time
DB-->>API: stream events or spill handle
API-->>App: result sets or windowed result
App->>Grid: build result view model
Grid->>API: dbResultWindow when spilled pages are needed
Important implementation details:
db_run_query_streamstreams batches for fast first paint.db_run_query_spillwrites huge results to a bounded Rust-side result store.db_result_windowpages spilled results back into the grid.db_cancelcancels active work through cancellation tokens.- The UI result grid handles sorting/filtering/editing for resident results.
- Spilled results are browse-first; server-side sort/filter is a separate workflow.
Shared Crate Layers
flowchart TB
app["apps/desktop/src-tauri"]
server["irodori-server"]
extension["irodori-extension"]
core["irodori-core"]
connection["irodori-connection"]
security["irodori-security"]
proxy["irodori-proxy"]
secureStore["irodori-secure-store"]
completion["irodori-completion"]
generate["irodori-generate"]
io["irodori-io"]
external["external git/crates<br/>irodori-sql, irodori-error, irodori-jobs"]
app --> core
app --> completion
app --> generate
app --> io
app --> proxy
app --> secureStore
app --> external
server --> core
server --> external
extension --> external
core --> connection
core --> security
core --> external
proxy --> core
secureStore --> core
completion --> external
generate --> external
io --> core
io --> external
Do not add a crate just because a future feature sounds independent. Start inside the owning app or crate, then split when there is a stable API, separate test cadence, or a real second consumer.
Extension Surface
Extensions are intentionally not the same as app internals.
flowchart LR
manifest["irodori.extension.json"]
sdk["TypeScript SDK<br/>../irodori-kit/packages/extension-sdk"]
generated["generated extension API"]
host["desktop extension host/store"]
app["workbench commands/results/themes"]
manifest --> sdk
generated --> sdk
sdk --> host
host --> app
Extension rules:
- Public extension payloads belong in
../irodori-kit/irodori-extension. - SDK convenience wrappers belong in
../irodori-kit/packages/extension-sdk/src. - App-only plugin registry and loading state belongs under
apps/desktop/src/features/extensions. - Templates must stay permissively licensed and validate through
make extension-manifests.
Parallel Agent Development
Parallel work is organized around explicit workstreams rather than informal file
ownership. The detailed policy lives in
parallel-agent-architecture.md, and the
machine-readable source is
registry/agent-workstreams.json.
The key split is:
- One coordinator agent owns registry and generated-catalog source files:
knowledge/engines.json,registry/catalog/*.json, andapps/desktop/src-tauri/src/db/engine.rs. - Connector agents are repeatable and own exactly one generated sibling
repository under
../irodori-extensions/irodori-extension-*. - Extension-host, DB-runtime, migration/diff, and workbench-UI agents own separate source trees and serialize changes only when shared contracts move.
- Generated outputs are changed by the owner of the generator input, not by downstream agents.
Validate the workstream map with:
node tools/docs/agent-workstreams.mjs
Adding A Feature
- Decide the owner.
- UI workflow:
apps/desktop/src/features/<area>. - Local privileged action:
apps/desktop/src-tauri/src/<area>. - Stable shared model: an existing crate, not a new crate by default.
- UI workflow:
- If TypeScript calls Rust, define or update the Rust DTO/command first.
- Regenerate bindings with
make desktop-typegen. - Wire the UI through
generated/irodori-api.ts, not handwritten invoke calls. - Add focused unit tests near the owning feature.
- Run the smallest relevant checks, then broaden if the boundary changed.
Typical checks:
make desktop-typegen-check
npm --prefix apps/desktop test
npm --prefix apps/desktop run build
cargo test --workspace
Current Refactor Pressure Points
These areas work but should be watched because they are high-change/high-size:
apps/desktop/src/app/AppWorkbench.tsx: integration point. Move feature logic into hooks, stores, or feature components when touching it.apps/desktop/src/features/connections/connection-transfer.ts: importer coverage is broad. Keep parsers test-backed.apps/desktop/src/sql/completion.ts: completion logic should continue moving towardirodori-completionwhen it becomes engine-independent.apps/desktop/src/theme/index.ts: theme normalization should stay data-driven.apps/desktop/src/features/results/components/WebGlResultGrid.tsx: rendering behavior should stay isolated from result model construction.
Architecture Guardrails
apps/desktopis allowed to orchestrate product UX.crates/*should not know about React, Tauri windows, or app layout.- Rust command payloads should use camelCase at the JSON/TS boundary.
- Long-running work should expose progress/cancel/logs through jobs.
- Huge data should stream or spill; do not buffer full result sets in the UI.
- Secret values should not be logged, copied into generated bindings, or stored in plain frontend state.
- Reference-project research belongs in docs or requirements, not copied code.
Local SQL generation
Irodori Table can generate SQL from natural language with a lightweight local model, designed so correctness comes from a real SQL grammar rather than from model size. A tiny quantized model runs entirely on-device; every token it emits is forced through a schema-specialized SQL grammar, and the result is parsed back and validated against the schema. Deterministic completion stays the default — this is an opt-in, offline generation path.
Why it’s correct by construction
A small model is unreliable on its own. The design removes that risk:
- Grammar-backed SQL structure — a real, dialect-aware SQL parser + AST + GBNF grammar
(
irodori-sql:ast.rs,parser.rs,grammar.rs). - Grammar-constrained decoding — the model can only sample tokens the GBNF grammar allows, so output is always syntactically valid.
- Schema projection — table/column names become closed grammar terminals, so a hallucinated relation is literally unsamplable.
- Planning before decoding — tables and foreign-key joins are resolved deterministically before the model runs, shrinking its job so a 0.5B model suffices.
- Scoped grammar — on large schemas the GBNF is projected down to just the planned tables (+ their FK neighbors), so the grammar a big DB produces stays small: faster decode, lower memory, and the model can’t even mention an irrelevant table.
- Validate + repair — output is parsed and every identifier is proven to exist; anything else is rejected, not returned.
Pipeline
NL prompt + connection schema
→ project (GenSchema → GBNF grammar + SchemaIndex)
→ plan (mentioned tables + FK joins + compact prompt)
→ decode (llama.cpp, grammar-constrained, greedy)
→ verify (parse + schema-validate + canonical re-render)
→ SQL inserted into the editor (never executed)
Crates
irodori-sql—ast,parser,grammar(the shared syntax tree). Pure Rust, dialect-parameterized.irodori-generate—project,plan,verify,runtimeand the orchestrator. Thellamafeature adds the embedded runtime (llama.rs). Without it (or without a model) the engine returnsunsupported/not found.- desktop (
src-tauri/src/ai) — theai_generate_sql,ai_engine_status,ai_set_provider, andai_get_providercommands. The schema comes from the existing completion metadata cache; the dialect from the connection engine.
Runtime & model
- Embedded llama.cpp via
llama-cpp-2, CPU only, behind thellamacargo feature (the C++ build stays opt-in, likeduckdb). - Default model: Qwen2.5-Coder-0.5B-Instruct Q4_K_M (~0.4 GB), strong at text-to-SQL at its size.
- Lightness: mmapped weights, model loaded once and reused, a fresh context per
request (KV cache freed between calls), small
n_ctx, capped threads, and the grammar prunes the token space so fewer decode steps are needed.
Providers — connect any model (extensibility)
Everything talks to one trait, GrammarModel (runtime.rs), so backends are
fully pluggable. The verify gate is what makes every provider safe: output is
parsed and schema-validated regardless of source, so a backend that can’t honor
the GBNF grammar just gets its mistakes rejected instead of prevented — never
returned as invalid/hallucinated SQL.
Built-in providers:
| Provider | Crate item | Feature | Notes |
|---|---|---|---|
| Embedded llama.cpp | LlamaSqlModel | llama | GBNF-constrained, fully local/offline |
| Ollama | OllamaModel | http | any local Ollama model (7B/14B/32B…) |
| OpenAI-compatible API | OpenAiCompatModel | http | OpenAI, Azure, OpenRouter, gateways, many self-hosted/Anthropic-compatible |
| External CLI | CommandModel | (none) | Claude Code, Codex, Copilot, or any command — reuses your subscription |
| Echo (tests) | EchoModel | (none) | deterministic stand-in |
The desktop selects a provider at runtime via ai_set_provider /
ai_get_provider (AiProviderConfig { kind, model, endpoint, apiKey, program,
args }), surfaced in the generate dialog’s “Model provider” section. The http
and CLI providers are compiled in by default, so external/subscription models
work without the heavy llama build; the embedded model stays opt-in. API keys
are held in memory only (persist via the OS keychain through
security_store_secret).
Adding another provider (e.g. Anthropic-native, a local server, a queue) is a new
impl GrammarModel plus one AiProviderKind arm — no pipeline changes.
Build & use
# Standard build: AI generation compiled out, everything else unaffected.
cargo build -p irodori-table-desktop
# With local generation (compiles llama.cpp; set TMPDIR for the C++ build):
TMPDIR=.irodori-local/cc-tmp cargo build -p irodori-table-desktop --features llama
The embedded model is read only when it already exists in the app data dir under
models/. The desktop UI does not start a background download job; preinstall
the model for local generation, or use Ollama / API / CLI providers.
Safety
AI generation is opt-in, only ever inserts SQL into the editor (it never runs it), and references only objects that exist in the connected schema. This keeps the A5SQL-style read-only / AI-disabled posture intact.
Follow-ups
- Optional admin tooling for preinstalling local models outside the desktop UI.
- Expand the grammar/AST beyond
SELECT(DML/DDL) over later iterations. - Optional idle-unload timer to drop the model from memory after inactivity.
Query plan explorer
Design for a cross-engine execution-plan viewer + analyzer: capture a query’s
EXPLAIN, normalize it, visualize it legibly, analyze it for problems,
and explain it in plain language — including teaching how to read the
metrics. AI narration is optional; the deterministic explanation always works.
Status: design (greenfield — no plan handling exists today beyond
explain analyze appearing in completion keywords).
Goals (from the ask)
- Capture and analyze execution plans.
- Explain the plan in natural language and identify likely bottlenecks.
- Teach how to read metrics such as cost, rows, loops, and elapsed time.
- Visualize the hot path with a tree/flame view.
- Normalize plan data across PG/MySQL/Oracle/SQL Server/ SQLite/Snowflake/Hive/Trino/DuckDB…
The core problem: every engine’s EXPLAIN is different
There is no portable plan format. The design’s spine is a per-engine capture + parser that lowers each native format into one normalized plan IR, after which visualization, analysis, and explanation are engine-agnostic.
| Engine | Capture | Native shape |
|---|---|---|
| PostgreSQL (+ CRDB/Yugabyte/Timescale/Neon) | EXPLAIN (FORMAT JSON[, ANALYZE, BUFFERS, VERBOSE]) <q> | JSON tree, est+actual |
| MySQL / MariaDB / TiDB | EXPLAIN FORMAT=JSON <q> · EXPLAIN ANALYZE <q> (8.0.18+) | JSON / tree text |
| SQL Server | SET SHOWPLAN_XML ON / SET STATISTICS XML ON | XML showplan |
| Oracle | EXPLAIN PLAN FOR <q> + DBMS_XPLAN.DISPLAY, or /*+ GATHER_PLAN_STATISTICS */ + DBMS_XPLAN.DISPLAY_CURSOR | row table / cursor stats |
| SQLite | EXPLAIN QUERY PLAN <q> | simplified tree |
| Snowflake | EXPLAIN USING JSON <q>; profile via GET_QUERY_OPERATOR_STATS() | JSON / operator stats |
| Trino / Presto / Hive | EXPLAIN (FORMAT JSON) <q> · EXPLAIN ANALYZE | JSON / text |
| DuckDB | EXPLAIN [ANALYZE] <q> (json) | JSON tree |
Each engine gets a PlanProvider that knows (a) the EXPLAIN SQL to issue and
(b) how to parse its output into the IR. This reuses irodori-sql’s
trait SqlDialect for identifier rendering and lives next to the existing
dialect/metamodel code.
Normalized plan IR
pub struct QueryPlan {
pub engine: DbEngine,
pub analyzed: bool, // EXPLAIN ANALYZE (actuals) vs estimate-only
pub root: PlanNode,
pub totals: PlanTotals, // total cost, total actual time, planning/exec ms
pub warnings: Vec<String>, // capture caveats (e.g. "estimates only")
}
pub struct PlanNode {
pub op: PlanOp, // canonical operator (below)
pub label: String, // engine's raw node name, preserved
pub relation: Option<String>, // table/index/CTE touched
pub est: NodeEstimate, // rows, cost (start/total), width
pub actual: Option<NodeActual>, // rows, loops, time_ms, returned (ANALYZE only)
pub io: Option<NodeIo>, // buffers/blocks read, spill bytes, network
pub detail: Vec<(String, String)>, // condition, filter, sort key, join type…
pub children: Vec<PlanNode>,
}
pub enum PlanOp { // engine names mapped to one vocabulary
TableScan, IndexScan, IndexOnlyScan, BitmapScan,
NestedLoop, HashJoin, MergeJoin,
Aggregate, GroupAggregate, HashAggregate, WindowAgg,
Sort, IncrementalSort, Limit, Materialize, Memoize,
Gather, Exchange, Subquery, CteScan, Result, ModifyTable, Other(String),
}
The IR carries both the engine’s raw label and the canonical PlanOp, so
visualization stays uniform while node cards can still show native terminology.
Analysis — deterministic heuristics first
A rule pass over the IR produces Finding { severity, node_path, title, explanation, suggestion }. These are engine-aware but deterministic (no AI),
so analysis is reliable and offline. Starter rules:
- Full scan of a large relation where a predicate could be indexed → suggest index on the filter/join column.
- Estimate vs actual skew (
actual_rows / est_rowsfar from 1, ANALYZE only) → planner mis-estimate; suggestANALYZE/stats refresh; explains why the plan shape may be wrong. - Hot subtree: node(s) accounting for the majority of total time/cost → “spend your effort here.”
- Sort/hash spilled to disk (buffers/spill bytes) → raise work_mem / add index to avoid the sort.
- Nested loop over a large outer/inner → likely should be hash/merge join.
- Row explosion across a join (output ≫ inputs) → missing/incorrect join key.
- Redundant materialize/sort, non-sargable predicate (function on indexed
column),
SELECT *width blowup.
Each finding maps to a node so the UI can highlight it on the tree.
Natural-language explanation — two layers
- Deterministic narrative (always on, offline). Template the IR + findings
into prose: “This query scans
orderssequentially (1.2M rows, ~78% of total time) because no index coversstatus, then hash-joins tocustomers. The planner expected 200 rows but got 48,000 — stale statistics. Biggest win: an index onorders(status).” This is the baseline and never depends on a model. - AI narration (opt-in). Feed the normalized plan + findings to a
GrammarModelprovider (the existingirodori-generatestack:LlamaSqlModelembedded,OllamaModel/OpenAiCompatModelover HTTP,CommandModelvia CLI) using unconstrained decoding for fluent prose and a tutoring “how would you fix this?” voice. Per the roadmap, AI is optional and audited — the deterministic narrative stands alone; AI only enriches it.
The IR (not raw EXPLAIN text) is what’s fed to the model, so the prompt is small, engine-neutral, and consistent across providers.
Metric glossary
A small, structured glossary keyed by (engine, metric) powers inline tooltips
and a “how to read this plan” panel:
- cost (PG): arbitrary units,
startup..total; only comparable within one plan, not across engines. - rows: estimate (and, with ANALYZE, actual); the est/actual ratio is the signal, not the absolute.
- loops (PG nested loop): a node’s time is
actual_time × loops. - actual time:
startup..totalms per loop. - buffers / blocks (PG
BUFFERS): cache vs disk reads — IO pressure. - width: bytes per row — wide rows = more memory/IO.
- SQL Server cost %, MySQL
filtered/rows, OracleCardinality/Bytes, etc.
This directly serves the metric glossary: the user learns what each number means and how to act on it, inline where the number appears.
Visualization — make the hot path pop
A new ResultMode = "plan", rendered in the result area alongside
grid/chart/graph/webgl/structure (features/results/components/ ResultBody.tsx dispatches on resultMode). A features/query-plan/ view with:
- Tree / flame view: collapsible operator tree; each node sized/heat-colored by its share of total time (or cost when estimate-only) so the expensive subtree is obvious at a glance.
- Node card: canonical op + raw label, relation, est vs actual rows with a skew badge, time/cost %, IO/spill, and the condition/filter/sort detail.
- Findings rail: the heuristic findings, each clicking-through to highlight its node; severity-colored.
- Explanation panel: the deterministic narrative, with an optional “Explain with AI” button (only if a provider is configured) and the glossary tooltips.
- Estimate ⇄ Actual toggle: estimate (plain
EXPLAIN, safe) vs actual (EXPLAIN ANALYZE, runs the query — see safety).
Safety — EXPLAIN ANALYZE executes the query
Plain EXPLAIN is read-only and always safe. EXPLAIN ANALYZE runs the
statement — dangerous for DML. Rules:
- Classify the statement with the existing read-only guard
(
../irodori-kit/irodori-serverguard::classify, already used for the headless API). - Offer ANALYZE freely for read-only queries.
- For writes: either refuse ANALYZE, or wrap in a transaction the engine can roll
back (
BEGIN; EXPLAIN ANALYZE …; ROLLBACK;on PG) with a loud confirm. Never silently execute a DML to profile it.
Where the code lives
- Query-plan module (new, engine-agnostic). The IR, per-engine EXPLAIN SQL +
parsers, the heuristic rules, and the deterministic narrative + glossary.
Depends on
irodori-sql(dialect) only; no DB driver. Start app-local underapps/desktop/src-tauri/src/query_plan/, then promote to a sibling shared repo only after the IR has a stable release/test boundary. - Capture command. Tauri
explain_query(connection, sql, { analyze }) -> QueryPlaninsrc-tauri/src/db/— issues the engine’s EXPLAIN via the existing pool and hands the output toirodori-plan. Headless:POST /v1/explain. - AI narration. Reuse
irodori-generateproviders via a thin free-textexplain_plan(plan, provider)path (sibling toai_generate_sql), opt-in. - UI.
features/query-plan/(tree/flame view, node cards, findings rail, explanation + glossary), wired asResultMode = "plan"; a “Explain plan” action/keybinding next to Run.
Phased plan
- IR + PostgreSQL provider (richest JSON, est+actual+buffers) end-to-end: capture → IR → tree view → 3–4 heuristics → deterministic narrative + glossary. This proves the whole pipe on one engine.
- More providers: SQLite (
EXPLAIN QUERY PLAN), MySQL JSON, DuckDB — fast wins; then SQL Server XML, Oracle DBMS_XPLAN, Snowflake/Trino. - Flame heat view + findings rail polish; estimate⇄actual toggle + ANALYZE safety guard.
- AI narration behind the existing provider config (opt-in), feeding the IR.
- Headless
/v1/explain+ a CLI verb for plan capture in automation.
Relationship to the data-diff design
Both new capabilities are engine-agnostic analysis crates over the same seams
(dialect, the db read path, the headless API, optional AI providers). irodori-diff
(data-verification-diff.md) and irodori-plan share
the pattern: lower heterogeneous engines into one IR, then analyze/present
uniformly. Worth keeping their crate conventions aligned.
Integrated terminal
A VSCode-style bottom terminal panel, rendered with xterm.js + WebGL for
Ghostty/WezTerm-class throughput, backed by a real PTY. Toggle it with
**Ctrl+\``** or the command palette ("Toggle Terminal"). It pairs with the AI CLI providers — run claude/codex` / any tool right in the app.
Architecture
xterm.js (WebGL) ──onData──▶ pty_write
▲ ▲
│ term.write(bytes) │ Tauri commands
base64 decode │
│ ▼
Channel<PtyEvent> ◀──── pty_spawn (portable-pty: shell in a PTY)
│ pty_resize / pty_kill
- Backend (
src-tauri/src/pty/mod.rs):portable-pty(wezterm’s cross-platform PTY).pty_spawnstarts the shell, a reader thread streams output base64-encoded over a TauriChannel(base64 preserves bytes across chunk boundaries);pty_write/pty_resize/pty_killdrive the session. Sessions live in aPtyStatemap and are dropped on exit/kill. - Frontend (
src/features/terminal/):TerminalViewbinds one xterm.js instance (fit + WebGL addons) to a PTY session;TerminalPanelis the tabbed bottom dock. PTY wrappers are hand-written insrc/lib/tauri/pty.ts(theChannelarg, like the query-stream wrapper). - Workbench:
terminal.togglecommand (palette + `Ctrl+``), docked as a fixed bottom panel below modals.
Notes & follow-ups
- Default shell:
$SHELL(unix) /%ComSpec%(windows); cwd defaults to the app’s working dir. - The dock is a fixed overlay for now (low conflict with the in-flight workbench refactor); a resizable, content-pushing split panel is a natural follow-up.
- Persisting open terminals / splitting panes are future enhancements.
Headless local data API (irodori-server)
An optional local HTTP server that exposes read and safe-write data operations over the same token-scoped auth, read-only-by-default SQL guard, and audit trail the desktop uses — for scripting, tests, and external tools. (PostgREST / DuckDB httpserver were behavior references; the implementation is independent.)
Endpoints
| Method + path | Purpose | Scope |
|---|---|---|
GET /health | liveness | read |
GET /v1/sources | list configured sources | read |
GET /v1/sources/{id}/objects | list tables/views | read |
POST /v1/sources/{id}/query | run SQL ({ "sql": "...", "maxRows": 1000 }) | read / write |
Every response is JSON; errors use { "error", "code" }. A query returns
{ columns, rows, rowCount, elapsedMs, truncated } (rows are a row-major matrix
of JSON cells, the same shape the desktop/web grids consume).
Safety model (layered, all pre-existing + now wired)
- Auth (
auth.rs): bearer tokens → scopes (read/write), constant-time compare. No tokens = open mode = read-only for anyone (localhost/dev); writes always require an explicitwrite-scoped token. - Read-only guard (
guard.rs): classifies each statement (ReadOnly/Write/Forbidden) after blanking strings/comments; multiple statements are forbidden. AWritestatement needs thewritescope and a writable source; otherwise403. - Audit (
audit.rs): one structured entry per request (JSON lines to stderr by default), success or rejection.
Architecture
server.rs—ApiServer::dispatch(method, path, auth, body) -> ApiResponseis transport-agnostic (unit-tested without sockets);serve(addr, server)is the hyper adapter.source.rs— theDataSourcetrait + a built-inSqliteDataSource(synchronousrusqliteonspawn_blocking, so it owns the statement and avoids the'static/Sendborrow constraints async SQLite drivers impose inside anasync_traitfuture). The desktop can implementDataSourceover its live connection registry to expose the same adapters/proxy/security.Registrymaps source ids →Arc<dyn DataSource>.
Run standalone
IRODORI_SERVER_ADDR=127.0.0.1:8787 \
IRODORI_SERVER_SQLITE=/path/to.db \
IRODORI_SERVER_WRITABLE=1 \
IRODORI_SERVER_TOKEN=secret \
cargo run -p irodori-server
curl -s -H 'authorization: Bearer secret' \
-d '{"sql":"select * from users limit 10"}' \
http://127.0.0.1:8787/v1/sources/default/query
Follow-ups
- Bounded streaming for large result sets (current SQLite source caps + flags
truncated; a streaming/cursor path mirrors the desktop’s spill design). - Parameterized queries (
params) and dedicated row read/insert/update/delete endpoints. - A desktop
DataSourceimpl over the live connection registry + a Tauriserver_start/server_stopcommand.
Local Knowledge Base
Irodori should keep a local, searchable memory of database specifications, release notes, DB-client product expectations, AI integration docs, and implementation notes.
The goal is to make future implementation and bug fixing less dependent on memory or scattered browser tabs.
Storage
- Generated SQLite DB:
knowledge/irodori-knowledge.sqlite - Schema:
knowledge/schema.sql - Source registry:
knowledge/sources.json - Refresh script:
tools/knowledge/refresh.mjs - Analysis script:
tools/knowledge/analyze.mjs - Query script:
tools/knowledge/query.mjs
The SQLite DB is intentionally ignored by Git. The schema and source registry are tracked.
Task Navigation
Use this document for the knowledge-base system itself: source registry shape, refresh/query workflow, source policy, and what kinds of facts belong in the local store. It should not duplicate the product backlog.
- Product capability strategy belongs in data-source-coverage-strategy.md and data-source-support-status.md.
- Release/task direction belongs in roadmap-1.0.md.
- Current code ownership belongs in implementation-architecture.md.
- Parallel-worker ownership and handoffs belong in
parallel-agent-architecture.md and the
table repo’s
docs/agent-workstreams.json.
When a task depends on vendor behavior or DB-client precedent, query this knowledge base first, then record the implementation outcome in the owning task doc. A knowledge snapshot or source-registry update is evidence for future work; it does not by itself close a product feature without linked implementation and verification.
Source Registry Schema
knowledge/sources.json is a JSON array. Each entry is one stable source that can
be registered into the sources table from knowledge/schema.sql.
Required fields:
id: stable lowercase kebab-case identifier. Do not rename it after snapshots or facts may reference it; add a replacement source instead.name: human-readable source name.product: product, project, or service this source documents.category: source family. Current values aredatabase,db_client,ai, andtooling.sourceType: document kind. Current values arespec,release_notes,driver_docs,product_docs, andoss_project.url: canonical upstream URL. It must be unique across the registry.
Optional fields:
official: defaults totrue; set tofalseonly for clearly labeled non-official references.cadence: refresh expectation such asweeklyormonthly; defaults toweekly.enabled: defaults totrue; set tofalseto keep a source registered but skip network refresh.notes: short reason this source matters to Irodori implementation work.
The refresh script maps sourceType to the SQLite source_type column and keeps
official, cadence, enabled, and notes synchronized on every run.
Usage
Initialize the DB and register sources without network access:
node tools/knowledge/refresh.mjs --no-fetch
Fetch the first few sources:
node tools/knowledge/refresh.mjs --limit 5
Fetch one source:
node tools/knowledge/refresh.mjs --source sqlite-changes
List registered sources:
node tools/knowledge/query.mjs
Search snapshots:
node tools/knowledge/query.mjs "ALTER TABLE"
Generate local facts and implementation notes from the latest stored snapshots:
node tools/knowledge/analyze.mjs
Preview generated facts without writing:
node tools/knowledge/analyze.mjs --dry-run
Analyze only text segments added since the previous stored snapshot for each source. This is the recommended mode for routine refreshes because it focuses implementation notes on new upstream behavior:
node tools/knowledge/analyze.mjs --changed-only
On the first snapshot for a source, --changed-only falls back to full analysis
so the source can be seeded. Add --strict-changed to skip sources without a
previous snapshot.
List or search generated facts and implementation notes:
node tools/knowledge/query.mjs --facts auth
node tools/knowledge/query.mjs --notes driver
What To Store
- Official release notes and migration notes.
- SQL syntax/reference pages.
- Non-SQL source references: Cypher, time-series SQL/native query docs, document/KV/search APIs, and distributed SQL operational metadata.
- Catalog/introspection references.
- Driver documentation and behavior changes.
- DB client feature docs and market scans.
- Source-specific GUI docs such as Neo4j Browser, InfluxDB UI/Data Explorer, MongoDB Compass, RedisInsight, and DbGate.
- AI/Copilot/MCP integration docs.
- Manual facts discovered while fixing bugs.
- Implementation notes linking a source fact to an Irodori component.
Source Policy
- Prefer official docs and release notes.
- Keep coverage across database specs, database release notes, DB-client product docs, AI/MCP references, and type/tooling references.
- Use versioned URLs where the upstream publishes stable versioned specs.
- Keep IDs stable even if a URL redirects or an upstream page is renamed.
- Add new
categoryorsourceTypevalues only with a matching documentation update here and downstream handling in the refresh/query code when needed. - Run JSON validation and
node tools/knowledge/refresh.mjs --no-fetchbefore marking registry changes done. - Store URL, source product, fetch time, and hash for every snapshot.
- Summarize implementation facts in our own words.
- Do not store proprietary docs that we do not have rights to retain.
- Do not treat scraped docs as vendored source code.
Automation Direction
- Local: run the refresh script manually while developing.
- Scheduled: later add a weekly GitHub Actions job or local cron that refreshes sources and opens a report.
- Large index builds: source snapshots, generated facts, implementation notes, schema metadata, and query-history search indexes must be built through the shared job runtime with progress, cancellation, checkpoint/resume, bounded memory, and disk-backed state where needed.
- Smarter extraction:
tools/knowledge/analyze.mjsstarts with deterministic rule-based classification for versions, breaking changes, SQL syntax, authentication, metadata, result UI, visualization, and driver-impacting changes. Add per-product extractors when a source needs higher precision. - ML/evaluation: any model-ranking or provider-evaluation dataset derived from knowledge snapshots must record source IDs, snapshot hashes, privacy inputs, metrics, and artifact hashes so runs are reproducible and auditable.
- Integration: surface relevant facts in the app when implementing a dialect feature or debugging a query issue.
Repository Boundaries And Archive Policy
This file is the public, repo-local version of the Irodori documentation layout.
Use it when deciding whether a document belongs in irodori-table, the public
mdBook, a samples repo, or the private archive.
Repositories
| Repository | Visibility | Owns |
|---|---|---|
irodori-table | Public | Desktop app, app-local crates, local knowledge tools, packaging templates, and generated docs consumed by the app/CI. |
irodori-docs | Public | Public mdBook/site, durable user/contributor docs, policy pages, reference pages, feature matrix, backlog/progress views, ADR-style docs, and public long-form explanations. |
irodori-samples | Public | Database compose files, seed data, and DB-specific sample query projects. |
irodori-sql | Public | Reusable SQL dialect, placeholder, metamodel, and schema-diff helpers. |
irodori-knowledge | Public | Shared error/job/knowledge crates used by this workspace. |
irodori-kit | Public | Shared Rust foundation crates, extension SDK, manifest schema, extension-dev helper, generated SDK API, starter templates, and packaging templates. |
irodori-migration | Public | Execution-free migration planning and schema/data-diff primitives that can be reused outside the desktop app. |
irodori-extension-* | Public per connector | One installable connector implementation per repository, usually generated under the local sibling parent ../irodori-extensions/. |
irodori-archive | Private | Historical internal planning/status snapshots, audits, private research notes, bulky discarded docs, and material that should not be public. |
What Stays In irodori-table
- Root project entry points:
README.md,CONTRIBUTING.md,SECURITY.md,ROADMAP.md. - Generated snapshots that are consumed by tooling or the desktop app:
registry/data-source-support-status.md, selectedregistry/cheatsheets/, andregistry/catalog/*.json. - Machine-readable coordination files that local tools validate, such as
registry/agent-workstreams.json. - Short repo-local pointers, such as
docs/README.mdand this boundary policy.
What Moves To irodori-docs
- Stable user guides and contributor guides.
- Public site pages.
- Policy pages: clean-room, licensing, security process, release process.
- Reference pages that should have durable public URLs.
- Feature matrix, implementation progress, backlog, and release-readiness pages.
- ADR-style decisions that explain why the system is shaped a certain way.
- Long-form feature architecture docs, including implementation architecture, migration/data-diff, local SQL generation, query plan explorer, integrated terminal, headless API, distribution, and store/package registration.
When a page is moved out, keep a local link from docs/README.md only if a code
workflow still needs to discover it from this repository.
What Moves To irodori-samples
compose.yaml, seed SQL/JS, and per-engine fixture data.- DB-specific sample query projects under
projects/<engine>/. db-feature-samples.jsonand sample catalog data.
This repo expects the samples repo as a sibling checkout by default:
git clone https://github.com/hjosugi/irodori-samples ../irodori-samples
Override the location with IRODORI_SAMPLES=/path/to/irodori-samples.
What Moves To irodori-archive
Archive instead of deleting when the material has historical value but is not a current public contract:
- superseded implementation plans;
- one-off status reports and audit dumps;
- raw product/research notes;
- internal screenshots or bulky generated exports;
- private planning context that should not be published;
- old docs that confuse current source-of-truth ownership.
Do not link private archive paths from public docs. If public context is needed,
write a short replacement summary in irodori-docs or this repo.
Generated-Doc Flow
Generated docs are edited at their inputs:
| Output | Edit Instead |
|---|---|
registry/data-source-support-status.md | knowledge/engines.json, registry/catalog/*.json, tools/docs/support-status.mjs |
registry/cheatsheets/*.md | knowledge/cheatsheets/*.json, the knowledge DB, tools/knowledge/cheatsheet.mjs |
registry/catalog/catalog.json | registry/catalog/index.json, tools/docs/build-extension-catalog.mjs |
Generated snapshots should be mirrored into irodori-docs for public reading.
Keep a Markdown snapshot in irodori-table only when a local generator, CI guard,
or app-consumed source needs it.
Parallel Agent Boundary
Use parallel-agent-architecture and agent-workstreams.json when assigning work to multiple coding agents. The default split is:
- app/runtime/registry contract changes stay in
irodori-table; - extension SDK, manifest schema, and template changes stay in
irodori-kitunderpackages/extension-sdk; - one connector implementation agent writes one
irodori-extension-*repository; - generated docs/catalog files are updated by the agent that owns the source data or generator;
- shared contracts are serialized through the coordinator workstream.
The check is:
node tools/docs/agent-workstreams.mjs
Decision Checklist
Before adding a new document, answer:
- Does app code or tooling consume it? Keep it here.
- Is it stable public documentation? Put it in
irodori-docs. - Is it a DB fixture or sample query catalog? Put it in
irodori-samples. - Is it historical/private/internal? Put it in
irodori-archive. - Is it generated? Edit the generator or source data, not the output.
Data Source Support Status
Last generated: 2026-06-26 JST (hand-authored seed; target is auto-generation
from irodori-table registry inputs).
This is the single inventory of what Irodori connects to today vs. what is
declared, planned, or not yet started. The authoritative source of truth is the
DbEngine registry in apps/desktop/src-tauri/src/db/engine.rs and the connect
dispatch in apps/desktop/src-tauri/src/db.rs. Roadmap intent lives in
https://hjosugi.github.io/irodori-docs/data-source-coverage-strategy.html;
this file reconciles intent against the code.
Managed-service verification procedures live outside the public user path; keep this page focused on selectable engine support and registry drift.
Status legend:
- Wired — has a production connect path and a dedicated adapter or a wire-compatible adapter it routes through.
- Verified — Wired and exercised against a real instance in
tests/integration_db.rsthrough the sample harness (make db-verify). - Pending — recognized by the engine enum, adapter scaffolding exists, but the connector intentionally returns a “not ready” result.
- Extension — recognized by the engine enum and published through the
extension marketplace; the app browses
registry/catalog/catalog.jsonand install/details stay inregistry/catalog/index.jsoninstead of being compiled into the core desktop build. - Recognized, extension required — present in
DbEnginebut rejected at connect byis_unimplemented_wire()until an installable connector extension is present. - Not registered — named in the roadmap/coverage strategy but absent from the
DbEngineenum — i.e. not selectable in the app at all yet.
1. Wired engines (selectable and connectable today)
| Engine | DbEngine id | Wire / driver | Adapter file | Port | Maturity | Shipped release build |
|---|---|---|---|---|---|---|
| PostgreSQL | postgres | Postgres / sqlx | db/postgres.rs | 5432 | Verified | Built-in |
| MySQL | mysql | MySQL / sqlx | db/mysql.rs | 3306 | Verified | Built-in |
| MariaDB | mariadb | MySQL wire / sqlx | (via mysql.rs) | 3306 | Verified | Built-in |
| SQLite | sqlite | file / sqlx | db/sqlite.rs | — | Verified (unit) | Built-in |
| Oracle | oracle | Thin TNS / oracle-rs | db/oracle.rs | 1521 | Verified | legacy-connectors |
| SQL Server | sqlserver | TDS / tiberius | db/mssql.rs | 1433 | Verified | legacy-connectors |
| DuckDB | duckdb | embedded libduckdb | db/duck.rs | — | Verified | duckdb |
| MotherDuck | motherduck | DuckDB service / extension | irodori.motherduck | 443 | Extension | Marketplace extension |
| CockroachDB | cockroachdb | Postgres wire / sqlx | (via postgres.rs) | 26257 | Verified | Built-in |
| YugabyteDB (YSQL) | yugabytedb | Postgres wire / sqlx | (via postgres.rs) | 5433 | Wired | Built-in |
| Redshift | redshift | Postgres wire / sqlx | (via postgres.rs) | 5439 | Wired (AWS, no local container) | Built-in |
| TimescaleDB | timescaledb | Postgres wire / sqlx | (via postgres.rs) | 5432 | Verified | Built-in |
| Neon | neon | Postgres wire / sqlx | (via postgres.rs) | 5432 | Wired | Built-in |
| H2 | h2 | Postgres wire / sqlx | (via postgres.rs) | 5435 | Wired (experimental) | Built-in |
| TiDB | tidb | MySQL wire / sqlx | (via mysql.rs) | 4000 | Wired | Built-in |
| MongoDB | mongodb | document / mongodb | db/mongo.rs | 27017 | Verified | legacy-connectors |
| Neo4j | neo4j | Bolt / neo4rs | db/neo4j.rs | 7687 | Wired (graph) — see cheatsheet | legacy-connectors |
| Redis | redis | RESP / redis | db/redis.rs | 6379 | Wired (adapter) | legacy-connectors |
| Cassandra | cassandra | CQL / scylla driver | db/cassandra.rs | 9042 | Wired (adapter) | legacy-connectors |
| ClickHouse | clickhouse | HTTP | db/clickhouse.rs | 8123 | Wired (HTTP client) | legacy-connectors |
| Snowflake | snowflake | HTTP | db/snowflake.rs | 443 | Wired (password/JWT subset) | legacy-connectors |
| BigQuery | bigquery | HTTP | db/bigquery.rs | 443 | Wired (HTTP client) | legacy-connectors |
| Bigtable | bigtable | gRPC/HTTP | db/bigtable.rs | 443 | Wired (adapter) | legacy-connectors |
| InfluxDB | influxdb | HTTP (SQL/v3) | db/influx.rs | 8086 | Wired (adapter) | legacy-connectors |
| ScyllaDB | scylladb | CQL / scylla driver | (via cassandra.rs) | 9042 | Wired (CQL-compatible) | legacy-connectors |
| QuestDB | questdb | Postgres wire / sqlx | (via postgres.rs) | 8812 | Wired | Built-in |
Maturity is a coverage signal, not a UX guarantee. “Wired (adapter)” means the connect/query path exists; first-class browsing, completion, editing, explain/profile, and visualization per source remain tracked by SRC tickets. Release builds pass
--features legacy-connectors,duckdb; local default development builds may omit feature-gated connectors for speed.
2. Pending (recognized, scaffolded, returns “not ready”)
None today. If an adapter has a dedicated Wire but intentionally returns a
not-ready error, list it here instead of mixing it with production connectors.
3. Recognized, extension required (in the enum, rejected at connect)
These appear in DbEngine but is_unimplemented_wire() rejects them before a
connection is opened. Most public connector targets ask the user to install
the matching installable connector from registry/catalog/index.json.
| Engine | DbEngine id | Family | Closest existing wire | Note |
|---|---|---|---|---|
| Memgraph | memgraph | Graph (Bolt/Cypher) | Neo4j | Installable connector; can reuse the Neo4j/Bolt path internally. |
| Qdrant | qdrant | Vector | — | Installable vector connector extension. |
| Milvus | milvus | Vector | — | Installable vector connector extension. |
| Pinecone | pinecone | Vector (HTTP) | — | Installable vector connector extension. |
| Cloud Spanner | cloudSpanner | Distributed SQL / Google API | CloudSpanner | Installable connector; Spanner SQL/catalog handling is separate from Postgres wire. |
| Trino / Presto | trinoPresto | Federated SQL | Jdbc | Installable JDBC-style connector extension. |
| Firebird | firebird | Relational | Jdbc | Installable JDBC-style connector extension. |
| Databricks / Spark SQL | databricks | Warehouse | Jdbc | Installable SQL Warehouse connector extension. |
| Elasticsearch | elasticsearch | Search | Search | Installable search connector extension with index/data-stream workflows. |
| OpenSearch | openSearch | Search | Search | Installable search connector extension with index/data-stream workflows. |
| Couchbase | couchbase | Document | Document | Installable document connector extension. |
| DynamoDB | dynamodb | Key-value | KeyValue | Installable key-value connector extension. |
| ArangoDB | arangodb | Graph / multi-model | Graph | Installable graph/multi-model connector extension. |
| Apache IoTDB | iotdb | Time-series | TimeSeries | Installable time-series connector extension. |
| Apache Hive | hive | Lakehouse / catalog | Jdbc | Installable Hive/Hive Metastore connector extension. |
| Amazon Athena | athena | Lakehouse / query-engine | Lakehouse | Installable Athena/Glue/workgroup connector extension. |
| Apache Iceberg | iceberg | Lakehouse | Lakehouse | Installable catalog-backed Iceberg connector extension. |
| AWS S3 Tables | s3Tables | Lakehouse | Lakehouse | Installable managed Iceberg connector extension. |
| Delta Lake | deltaLake | Lakehouse | Lakehouse | Installable Delta Lake connector extension. |
| Apache Hudi | hudi | Lakehouse | Lakehouse | Installable Hudi connector extension. |
4. Not registered (roadmap intent, not in the engine enum yet)
Named in the public data-source coverage strategy / feature matrix but
not selectable in the app — adding any of these starts with a new DbEngine
variant + Wire + adapter.
All roadmap sources currently promoted into the registry are listed above. Keep this section for future coverage-strategy ideas that are not selectable in the app yet.
5. Managed wire-compatible targets
These should not become separate DbEngine variants unless they need native API
surface beyond connection templates. They route through existing adapters:
| Target | Route through | Status | Product work |
|---|---|---|---|
| Supabase Postgres | postgres | Covered by Postgres wire; needs preset/docs | Direct vs. pooler connection strings, SSL, RLS notes, hosted extensions such as pgvector. |
| Amazon Aurora PostgreSQL | postgres | Covered by Postgres wire; needs preset/docs | Writer/reader/custom endpoint hints, IAM auth, cluster topology. |
| Amazon Aurora MySQL | mysql | Covered by MySQL wire; needs preset/docs | Writer/reader/custom endpoint hints, IAM auth, cluster topology. |
| Google Cloud SQL for PostgreSQL | postgres | Covered by Postgres wire; needs preset/docs | Public/private IP, Auth Proxy, IAM DB auth, SSL cert handling. |
| Google Cloud SQL for MySQL | mysql | Covered by MySQL wire; needs preset/docs | Public/private IP, Auth Proxy, IAM DB auth, SSL cert handling. |
| Google Cloud SQL for SQL Server | sqlserver | Covered by TDS path; needs preset/docs | Public/private IP, Auth Proxy, SQL Server connection-string guidance. |
6. Gaps worth deciding on
- Vector DBs are extension-first. Qdrant/Milvus/Pinecone are registry entries with marketplace extensions; core still needs the shared vector source-type contract for collection/index browsing and similarity-search query surfaces.
- Memgraph is extension-first. It speaks Bolt/Cypher like Neo4j; the extension can reuse the Neo4j path internally before core promotes it to a wired adapter.
- ScyllaDB now rides the existing
cassandra.rsCQL path; the remaining work is verification against a real ScyllaDB instance and source-specific UX polish. - Iceberg/lakehouse is now extension-first: Apache Iceberg, S3 Tables, Delta Lake, Hudi, Hive, and Athena all have marketplace connectors. Core still needs shared table/catalog UX and execution-backend contracts for those extensions.
When section 1-4 membership changes, regenerate this page from the registry inputs rather than hand-editing the mirrored snapshot.
Engine Connection & Query Reference
For every database Irodori supports: how to connect, the query model, and the
driver/dialect quirks. This doubles as the basis for the per-engine SqlDialect
(SRC-001a) and as a reference for extension authors. All engines go through the
same Connection trait (apps/desktop/src-tauri/src/db/).
Related docs: data-source-support-status.md is the coverage inventory (what
connects today vs. what is declared/planned), and cheatsheets/ holds the
task-oriented, copy-pasteable per-engine pages. Generated support-status and
cheatsheet snapshots are mirrored from the registry and knowledge inputs in
irodori-table. This file stays the deep driver/decoding reference.
Coverage at a glance
| Engine | Wire / driver | Default port | Query model | Test (tests/integration_db.rs / unit) | Container |
|---|---|---|---|---|---|
| PostgreSQL | postgres / sqlx | 5432 | SQL | postgres_samples | samples/postgres |
| MySQL | mysql / sqlx | 3306 | SQL | mysql_samples | samples/mysql |
| MariaDB | mysql wire / sqlx | 3306 | SQL | mariadb_connect | samples/mariadb |
| TimescaleDB | postgres wire / sqlx | 5432 | SQL | timescaledb_samples | samples/timescaledb |
| CockroachDB | postgres wire / sqlx | 26257 | SQL | cockroachdb_connect | samples/cockroachdb |
| YugabyteDB | postgres wire (YSQL) / sqlx | 5433 | SQL | yugabytedb_connect | samples/yugabytedb |
| TiDB | mysql wire / sqlx | 4000 | SQL | tidb_connect | samples/tidb |
| SQL Server | TDS / tiberius | 1433 | SQL | sqlserver_samples | samples/sqlserver |
| DuckDB | embedded libduckdb | — | SQL | duckdb_in_memory | none (embedded) |
| MongoDB | document / mongodb | 27017 | documents | mongo_samples | samples/mongodb |
| SQLite | file / sqlx | — | SQL | sqlite_connect_and_query_round_trip (unit) | none (file) |
| Oracle | thin TNS / oracle-rs | 1521 | SQL | oracle_samples | samples/oracle |
| Redshift | postgres wire / sqlx | 5439 | SQL | — (AWS-only, no local container) | — |
Run them with make db-verify DB=<engine> or make db-all. Env-gated tests
skip unless the matching IRODORI_* variable is set; the sample harness sets it
per engine.
Connection syntax
Irodori accepts either structured fields (host/port/user/password/
database) or a raw url/DSN that overrides them.
| Engine | URL / DSN form |
|---|---|
| PostgreSQL & wire-compatible | postgres://user:pass@host:5432/db |
| CockroachDB (insecure) | postgres://root@host:26257/defaultdb?sslmode=disable |
| YugabyteDB (YSQL) | postgres://yugabyte@host:5433/yugabyte?sslmode=disable |
| MySQL / MariaDB / TiDB | mysql://user:pass@host:3306/db |
| SQLite | sqlite://path/to.db?mode=rwc or sqlite::memory: |
| SQL Server (ADO) | server=tcp:host,1433;User Id=sa;Password=…;TrustServerCertificate=true |
| DuckDB | a file path or :memory: (in database/url) |
| MongoDB | mongodb://user:pass@host:27017/db?authSource=admin |
| Oracle | structured host/port/user/password/service fields |
Per-engine notes
PostgreSQL (+ CockroachDB, YugabyteDB, Redshift, TimescaleDB)
- Driver: sqlx native
PgPool. The wire-compatible engines reuse it; only the default port and a few catalog quirks differ (modeled later by the metamodel). - Version:
select version(). - Identifier quoting: ANSI double quotes —
"My Col"; escape"by doubling. - Paging:
LIMIT n OFFSET m. - Decoding:
NUMERIC→string (exact, viaBigDecimal),TIMESTAMPTZ→RFC3339,TIMESTAMP/DATE/TIME→string,JSON/JSONB→object,UUID→string,BYTEA→\xHEX, bool/ints/floats native. - Quirks: arrays decode best-effort to text today (rich array decode is a
follow-up); CockroachDB omits some
OID-typed system columns tools expect.
MySQL / MariaDB / TiDB
- Driver: sqlx native
MySqlPool. - Version:
select version(). - Identifier quoting: backticks —
`My Col`. - Paging:
LIMIT n OFFSET m(orLIMIT m, n). - Decoding:
DECIMAL→string,DATETIME/TIMESTAMP/DATE→string,JSON→object,BLOB/BINARY→\xHEX, ints/floats/strings native. - Quirks: MySQL 8.4 defaults to
caching_sha2_password; sqlx handles it over a non-TLS connection via the server’s RSA public key. MariaDB defaults tomysql_native_password. TiDB speaks the MySQL protocol on port 4000.
SQLite
- Driver: sqlx native
SqlitePool, capped at one connection. - Version:
select sqlite_version(). - Quoting: double quotes or backticks.
- Decoding: dynamically typed — values are decoded by trying integer, real,
text, then blob (
\xHEX). - Quirks: single writer;
:memory:is per-connection (use a file to share).
SQL Server
- Driver: pure-Rust
tiberius(TDS) — no SQL Server client library. - Version:
select @@version(first line kept). - Quoting: brackets —
[My Col](or ANSI"withQUOTED_IDENTIFIER ON). - Paging:
OFFSET n ROWS FETCH NEXT m ROWS ONLY(2012+), orTOP n. - Decoding (MVP): bool/int/float/string. Decimals currently come back as float (lossy) and datetimes/binary as null — precision-safe decimals and temporals are a tracked follow-up (EXEC-009b).
- Quirks: tiberius sends statements via
sp_executesql, so local#temptables are scoped away between calls — use##globaltemp tables, real tables, or (for self-contained checks) aVALUEStable constructor:select a,b from (values (1,'x')) v(a,b).
DuckDB (--features duckdb)
- Driver: embedded libduckdb. The
bundledbuild compiles libduckdb (C++) and is heavy — link a prebuilt/system libduckdb to skip the compile. - Version:
select version(). - Quoting: double quotes.
- Paging:
LIMIT n OFFSET m. - Decoding: rich (bool/ints/uints/float/double/text/blob); other types render as their text form.
- Quirks: statements are classified — DDL/DML run through
execute, only row-returning statements throughquery; column metadata is read after execution (DuckDB materializes the schema then). This avoids a driver panic.
MongoDB (document store — not SQL)
- Driver:
mongodbcrate (pure Rust). - Version:
buildInfo.version. - “Query”: a bare collection name (e.g.
customers), or a JSON object{ "collection": "orders", "filter": { "tier": "gold" } }. Documents project to a table by the ordered union of top-level keys (missing keys → null); values render as relaxed extended JSON (ObjectId→{ "$oid": "…" }, dates → ISO). - Quirks: no SQL. Aggregation pipelines, nested-field projection, and sort are
follow-ups (SRC-012). Auth usually needs
?authSource=adminfor the root user.
Oracle
- Driver: pure-Rust thin TNS through
oracle-rs; no Oracle Instant Client is required for the default path. - Connection: descriptor
//host:1521/service, or structured host/port/user/ password/database fields.databasecan be a service name,service:<name>, orsid:<name>. Wallet paths can be supplied on the URL query aswalletandwallet_password. - Explain:
EXPLAIN PLAN FOR ...returnsDBMS_XPLAN.DISPLAYoutput as a one-column result set.
Bounded results (all engines)
Every engine streams rows and stops at max_rows (default 10,000), returning
truncated: true when more remain — so a select * over a 10M-row table stays
memory-bounded instead of exhausting RAM. Full extraction is run-to-file (IO-001);
optional disk offload for very large windows is EXEC-010.
DB Feature Samples
samples/db-feature-samples.json is the source of truth for DB-specific sample
projects, feature checks, and official learning resources. It is intentionally
machine-readable so the repository docs and public website can stay aligned with
the engine registry.
Local sample projects
Use these when you want to check DB-specific behavior in Irodori Table beyond the generic connection smoke test.
| Engine | Sample file | Verification command | Focus |
|---|---|---|---|
| PostgreSQL | samples/projects/postgres/queries.sql | make db-verify DB=postgres | JSONB, arrays, GIN, extensions, explain JSON |
| MySQL | samples/projects/mysql/queries.sql | make db-verify DB=mysql | JSON functions, FK metadata, windows, explain JSON |
| MariaDB | samples/projects/mariadb/queries.sql | make db-verify DB=mariadb | JSON_VALID/JSON_VALUE, recursive CTEs, windows |
| SQLite | samples/projects/sqlite/queries.sql | cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml sqlite | Embedded SQL, JSON, FTS5, PRAGMA |
| DuckDB | samples/projects/duckdb/queries.sql | cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml --features duckdb duckdb_in_memory | Local analytics, structs, summarize, explain |
| SQL Server | samples/projects/sqlserver/queries.sql | make db-verify DB=sqlserver | T-SQL JSON, identity, TOP, OFFSET/FETCH |
| Oracle | samples/projects/oracle/queries.sql | make db-verify DB=oracle | Thin TNS, SQL/JSON, analytic functions, DBMS_XPLAN |
| MongoDB | samples/projects/mongodb/queries.js | make db-verify DB=mongodb | Collection query, JSON filter, aggregation reference |
| TimescaleDB | samples/projects/timescaledb/queries.sql | make db-verify DB=timescaledb | Hypertables, time_bucket, time-series metadata |
| CockroachDB | samples/projects/cockroachdb/queries.sql | make db-verify DB=cockroachdb | unique_rowid, UPSERT, range inspection |
| YugabyteDB | samples/projects/yugabytedb/queries.sql | make db-verify DB=yugabytedb | YSQL, split tablets, table properties |
| TiDB | samples/projects/tidb/queries.sql | make db-verify DB=tidb | MySQL wire, tidb_version, shard_row_id_bits, explain analyze |
Reference-only engines
Some engines are wired but cloud-only, hosted-only, or still missing a local
verification fixture. Their entries stay in samples/db-feature-samples.json so
the capability map remains complete: Redshift, Neon, H2, Neo4j, Redis,
Cassandra, ClickHouse, Snowflake, BigQuery, Bigtable, InfluxDB, Memgraph,
Qdrant, Milvus, and Pinecone.
Managed wire-compatible targets
These are not new low-level adapters. They should be surfaced as connection templates/presets that route through existing engines.
| Target | Route through | Focus |
|---|---|---|
| Supabase Postgres | postgres | Direct/pooler connection strings, SSL, RLS-aware browsing, hosted Postgres extensions such as pgvector |
| Amazon Aurora | postgres or mysql | Aurora PostgreSQL/MySQL endpoints, reader/writer endpoint guidance, IAM auth, cluster topology |
| Google Cloud SQL | postgres, mysql, or sqlserver | Public/private IP, Cloud SQL Auth Proxy, IAM DB auth, SSL certs, instance metadata |
Lakehouse targets
Iceberg and S3 Tables are not SQL wire-compatible databases. They need a catalog/table-format connection model plus an execution backend.
| Target | Route | Focus |
|---|---|---|
| Apache Iceberg | REST/Hive/AWS Glue/JDBC catalogs + object store credentials | Catalog, namespace, table, schema, partition, snapshot, manifest, and metadata browsing |
| Amazon S3 Tables | Managed Iceberg table buckets | Table buckets, namespaces, tables, AWS IAM, and query execution through Athena/Redshift/Spark-compatible engines |
Checks
Run the catalog guard directly:
node tools/docs/db-feature-samples.mjs
It is also part of:
make docs-check
The check fails when a registered engine has no catalog entry, a sample project points at a missing file, a local compose sample is not represented, or an engine has no official resource link.
Distribution & updates
How users get Irodori Table and how it updates. Current public release:
0.6.0 (v0.6.0, published 2026-07-02).
Already in place
.github/workflows/release.yml — on a v* tag push, tauri-action builds
installers for macOS, Windows (.msi/NSIS), and Linux
(.deb/.rpm/.AppImage) on the matrix runners and creates a GitHub Release.
The download channel is live today; publish a release tag such as v0.6.0.
Channel matrix
| Channel | For | Status | Notes |
|---|---|---|---|
| GitHub Releases (installers) | end users | ✅ exists | release.yml; cut by tagging the current release, e.g. v0.6.0 |
| Tauri in-app updater | end users (auto-update) | ⬜ next | the fastest update path for the GUI; needs a signing key |
| Terminal installer download | end users | ✅ exists | use gh release download and install the .deb, .rpm, .AppImage, .dmg, or .msi |
cargo install --git | Rust devs (headless server) | ✅ exists | installs irodori-server from irodori-kit, not the desktop app |
| crates.io | Rust devs | ⬜ later | crates.io forbids git/path deps; all irodori-* must be published first |
| Homebrew cask / Scoop / winget | mac/Windows | ⬜ later | manifests auto-bumped from releases |
| AUR / Flatpak | Linux | ⬜ later | from releases |
Public registration text, support/privacy/disclaimer URLs, and package manager
channel notes are collected in store-registration.md.
Package-manager manifests are still a future packaging task; do not link to
template paths until those files exist in irodori-table.
Quick terminal install
Use GitHub CLI to fetch the newest matching release asset without opening a
browser. When no release tag is passed, gh release download uses the latest
release:
tmp="$(mktemp -d)"
gh release download --repo hjosugi/irodori-table --pattern "*.deb" --dir "$tmp"
sudo apt install "$tmp"/*.deb
Replace the pattern and install command as needed:
| Platform | Pattern | Install command |
|---|---|---|
| Debian/Ubuntu | *.deb | sudo apt install "$tmp"/*.deb |
| Fedora/RHEL | *.rpm | sudo dnf install "$tmp"/*.rpm |
| Linux portable | *.AppImage | chmod +x "$tmp"/*.AppImage && "$tmp"/*.AppImage |
| macOS | *.dmg | open "$tmp"/*.dmg |
| Windows PowerShell | *.msi | launch the downloaded .msi |
The current v0.6.0 assets are:
Irodori.Table_0.6.0_amd64.debIrodori.Table-0.6.0-1.x86_64.rpmIrodori.Table_0.6.0_amd64.AppImageIrodori.Table_0.6.0_x64_en-US.msiIrodori.Table_0.6.0_x64-setup.exeIrodori.Table_0.6.0_aarch64.dmgIrodori.Table_aarch64.app.tar.gz
On “cargo is fastest”
cargo install only installs Rust binaries. It is not a desktop app installer:
the Tauri app bundles a webview, native packaging metadata, and a built frontend.
Use GitHub Release installers for the desktop app.
For the headless local HTTP API, install irodori-server from irodori-kit:
cargo install --git https://github.com/hjosugi/irodori-kit --tag v0.5.0 --locked irodori-server
The old irodori-table repo command is no longer correct because
irodori-server moved to irodori-kit.
Recommended order
- Tag the current release → installers ship immediately (channel already
built; for the current docs, that means
v0.6.0). - Tauri updater for in-app auto-update (the real “get updates” for the GUI):
cd apps/desktop && npm run tauri signer generate→ keypair.- Add the private key as the
TAURI_SIGNING_PRIVATE_KEYGitHub Actions secret. - In
tauri.conf.json: setbundle.createUpdaterArtifacts = trueandplugins.updaterwith the public key + anendpointsentry pointing at the releaseslatest.json(tauri-action emits it per release).
- Keep desktop terminal installs installer-based — document
gh release downloadpaths for release assets; keepcargo installscoped to theirodori-kitheadless server. - Package managers (brew/scoop/winget/AUR/Flatpak) once you want them — each is a small manifest auto-updated from the GitHub Release assets.
Store and Package Registration
This is the public registration pack for Irodori Table. It collects the text, URLs, IDs, assets, and per-channel checklist needed for app stores and package managers. Keep secrets, tax/banking data, personal addresses, signing certificates, app-specific passwords, and store account IDs out of this file. Use a private local note or private archive for operational submission notes.
Current public release: 0.6.0.
Public listing metadata
| Field | Value |
|---|---|
| Product name | Irodori Table |
| Generic name | SQL workbench / database client |
| App identifier | dev.irodori.table |
| Repository | https://github.com/hjosugi/irodori-table |
| Homepage | https://hjosugi.github.io/irodori-docs/ |
| Releases | https://github.com/hjosugi/irodori-table/releases |
| Documentation | https://hjosugi.github.io/irodori-docs/ |
| Support URL | https://hjosugi.github.io/irodori-docs/support.html |
| Privacy URL | https://hjosugi.github.io/irodori-docs/privacy.html |
| Disclaimer URL | https://hjosugi.github.io/irodori-docs/disclaimer.html |
| License | MIT OR 0BSD |
| Source license URL | https://github.com/hjosugi/irodori-table/blob/main/LICENSE |
| Category | Developer Tools, Database, Productivity |
| Age rating baseline | Developer tool; no user-generated public content |
| Paid content | None |
| Ads / tracking | None in this repository |
| Account required | No hosted Irodori account required |
| Primary binary | Tauri desktop app |
| Headless binary | irodori-server from irodori-kit |
Package IDs
| Channel | Suggested ID |
|---|---|
| Tauri app identifier | dev.irodori.table |
| GitHub Releases | irodori-table |
| Homebrew cask | irodori-table |
| Scoop | irodori-table |
| winget | Irodori.Table |
| Chocolatey | irodori-table |
| AUR binary package | irodori-table-bin |
| Flatpak | dev.irodori.table |
| Snap | irodori-table |
| crates.io binary crate | None yet; irodori-server is git-installable from irodori-kit |
Listing copy
Short description:
Open-source SQL workbench for querying, inspecting, and editing data across multiple database engines.
Japanese short description:
複数のデータベースを軽く扱うためのオープンソース SQL ワークベンチ。
Long description:
Irodori Table is an open-source desktop database workbench built with Rust, Tauri, React, and CodeMirror. It focuses on fast SQL editing, schema-aware completion, Vim-friendly keyboard workflows, large-result browsing, query plan inspection, import/export, and extension-ready database connectivity.
The app is local-first and does not require a hosted Irodori account. It connects to database servers, local files, and optional AI/model providers only when configured by the user.
Irodori Table is currently a development preview. Review SQL, backups, and target connections before running destructive commands.
Japanese long description:
Irodori Table は Rust / Tauri / React / CodeMirror で作られた オープンソースのデスクトップ DB ワークベンチです。SQL 編集、schema-aware completion、Vim に配慮したキーボード操作、大きな結果セットの閲覧、query plan の確認、import/export、拡張可能な接続機構を重視しています。
ホスト型の Irodori アカウントは不要です。ユーザーが設定したデータベース、 ローカルファイル、任意の AI/model provider にだけ接続します。
現在は development preview です。破壊的な SQL を実行する前に、対象接続、 バックアップ、実行内容を必ず確認してください。
Feature bullets:
- SQL editor with CodeMirror, formatting, snippets, command palette workflows, and Vim mode.
- Schema navigation, metadata inspection, completion, ERD, and query plan views.
- Result grid designed for large result sets with copy/export and row details.
- Connection workflows for local and remote database engines.
- Local-first desktop app with open-source release artifacts.
- Extension-oriented architecture for future connector packages.
Keywords:
SQL, database, PostgreSQL, MySQL, SQLite, DuckDB, Tauri, Rust,
developer tools, query editor, data browser, database client, Vim.
Required public pages
These pages are published from this mdBook by GitHub Pages:
- https://hjosugi.github.io/irodori-docs/support.html
- https://hjosugi.github.io/irodori-docs/privacy.html
- https://hjosugi.github.io/irodori-docs/disclaimer.html
The corresponding editable Markdown sources are:
Asset inventory
Current app/repository assets:
apps/desktop/src-tauri/icons/icon.pngapps/desktop/src-tauri/icons/icon.icnsapps/desktop/src-tauri/icons/icon.icoapps/desktop/src-tauri/icons/StoreLogo.pngapps/desktop/src-tauri/icons/Square*.pngsrc/irodori-icon.svg
Still needed before store submission:
- screenshots for macOS, Windows, Linux;
- at least one 16:9 product screenshot showing the workbench;
- optional short demo GIF/video for stores that support rich media;
- signed/notarized release artifacts where the channel requires them.
- committed package-manager, desktop-entry, and appstream manifest templates if those channels become active.
Channel checklist
GitHub Releases
Status: already wired by .github/workflows/release.yml.
Before publishing a release:
- run the release dry run;
- verify generated bindings and frontend build;
- verify release artifacts on each platform;
- fill release notes with known limitations and checksums;
- publish the draft release only after artifact names and signatures are stable.
Tauri updater
Status: next.
Needed:
- generate the Tauri updater signing key;
- store the private key in GitHub Actions secrets;
- commit the public key and updater endpoint in
tauri.conf.json; - emit updater artifacts from release builds;
- document rollback when an updater artifact is bad.
Homebrew cask
Status: planned; no template is committed yet.
Create a cask after the macOS release asset and sha256 are available. Submit to the appropriate tap or to the project-owned tap first.
Scoop
Status: planned; no template is committed yet.
Create a manifest after the Windows portable zip or installer strategy is stable. A portable zip is usually cleaner for Scoop than an interactive installer.
winget
Status: planned; no template is committed yet.
Create manifests after the Windows installer URL, sha256, publisher name, installer type, and installer switches are final.
Chocolatey
Status: planned; no template is committed yet.
Create a package if Chocolatey is a target channel. Keep the install script non-interactive and checksum-pinned.
AUR
Status: planned; no template is committed yet.
Create a PKGBUILD for irodori-table-bin once the Linux AppImage artifact
name and checksum are stable.
Flatpak / Flathub
Status: design work needed.
Flatpak needs a sandboxed runtime plan, file/network permissions, appstream metadata, icon assets, and a stable build source. Treat this as a separate packaging project.
Snap
Status: design work needed.
Snap needs confinement choices, interface declarations, metadata, and store review. Treat this as separate from the existing AppImage path.
crates.io
Status: later.
The current git install path is:
cargo install --git https://github.com/hjosugi/irodori-kit --tag v0.5.0 --locked irodori-server
crates.io publication requires all irodori-* git/path dependencies to be
published or removed from the publishable crate graph.
Private doc boundary
Keep this public:
- product description, screenshots, homepage/support/privacy URLs;
- package IDs, release URLs, checksums, and manifest plans;
- public troubleshooting and security-disclosure process.
Keep private:
- Apple Developer, Microsoft Partner Center, Snapcraft, Flathub, Chocolatey, and package registry account IDs;
- legal entity details, addresses, phone numbers, tax forms, and banking data;
- signing certificates, private keys, app-specific passwords, notarization credentials, API tokens, and recovery codes;
- review conversation history that includes account-specific data;
- release-blocking legal decisions that have not been approved for publication.
Official references
Re-check these before submitting because store and package-manager requirements change:
- Tauri distribution: https://v2.tauri.app/distribute/
- Tauri updater: https://v2.tauri.app/plugin/updater/
- Homebrew Cask Cookbook: https://docs.brew.sh/Cask-Cookbook
- Windows Package Manager manifests: https://learn.microsoft.com/en-us/windows/package-manager/package/manifest
- Scoop app manifests: https://github.com/ScoopInstaller/Scoop/wiki/App-Manifests
- Chocolatey package creation: https://docs.chocolatey.org/en-us/create/create-packages/
- Arch package guidelines: https://wiki.archlinux.org/title/Arch_package_guidelines
- Flathub submission: https://docs.flathub.org/docs/for-app-authors/submission
- Snapcraft release docs: https://snapcraft.io/docs/releasing-your-app
- App Store Connect app information: https://developer.apple.com/help/app-store-connect/manage-app-information/set-app-information/
- Microsoft Store developer account setup: https://learn.microsoft.com/en-us/windows/apps/publish/partner-center/open-a-developer-account
A5:SQL Mk-2 Reference Notes
Last reviewed: 2026-06-26 JST.
Source: https://a5m2.mmatsubara.com/
License Boundary
A5:SQL Mk-2 is distributed as freeware, and the official site says development happens in a private GitHub repository. Treat it as public site / public behavior reference only. Do not copy source code, screenshots, icons, UI wording, exact layout, or private implementation details.
Use this note to turn A5’s useful database-development workflows into Irodori-owned requirements and tests. Its UI is not the target.
Useful Reference Points
- Oracle-aware workflows: A5 supports Oracle client and direct connection modes, explain plans, PL/SQL procedure execution, and PL/SQL debugging. Irodori should keep Oracle first-class instead of treating it as an enterprise afterthought.
- Deep SQL completion: The official site calls out table/column completion driven by SQL parsing, including CTEs and subqueries. This is a good bar for deterministic completion depth.
- Execution plan workflows: A5 exposes access plans for Oracle, DB2, SQL Server, MySQL, and PostgreSQL. Irodori should normalize explain entry points while letting each dialect keep its plan-specific details.
- SQL designer and analysis: GUI query design is useful for users who inspect or explain joins visually. Irodori can support this later through schema-aware query builders without copying A5’s layout.
- Multi-statement execution: A5 handles semicolon, slash-only lines, and
GO-style delimiters, with run-current, run-after-caret, and run-all modes. Irodori should keep statement parsing explicit and dialect-aware. - Result comparison: Running the same SQL twice and comparing multiple result sets is useful for integration/regression evidence. This maps to Irodori’s result diff and saved-run history model.
- Excel evidence workflows: A5 can export multiple result sets to Excel and use that output as test evidence. Irodori should offer structured evidence export, but avoid making Excel the only durable artifact.
- Comment pseudo-instructions: A5 can read directives from SQL comments to set result titles and behavior. Irodori already has Query Magics; the useful idea is an auditable, visible command layer, not hidden magic that changes execution unexpectedly.
- Table editor + spreadsheet bridge: Excel output and paste-back editing are strong operator workflows. Irodori should keep clipboard and tabular paste semantics first-class while preserving safe transaction review.
- Bulk import/export and dummy data: CSV-compatible import/export, whole-table transfer, and dummy test-data generation are worth tracking under IO and QA.
- ERD and definition documents: A5 can reverse-generate ER diagrams, emit DDL, print/export diagrams, and produce table definition documents. Irodori should connect ERD, DDL generation, and docs export as one schema-comprehension flow.
- Control panels: Oracle, PostgreSQL, and MySQL management panels are useful as source-specific admin plugins, not as hardwired core UI.
- Read-only / AI-disabled editions: A5’s separate read-only and AI-disabled downloads are a strong product signal. Irodori should expose workspace policies for read-only mode, production guardrails, and AI-disabled environments.
Not Directly Portable
- A5 is Windows-first, while Irodori must stay cross-platform.
- A5’s interface density and workflow shape are not the target; use the feature coverage, not the UI expression.
- Excel-centric evidence is valuable, but Irodori should also support neutral artifacts such as CSV/JSON/Markdown/Parquet and signed run metadata.
- Oracle/DB2/SQL Server-specific features should remain dialect plugins or adapter-owned panels, not cross-engine assumptions.
- Comment directives must be visible, testable, and safe. Hidden behavior changes inside ordinary SQL comments can surprise users.
Candidate Backlog Follow-Ups
CMPL-003/004: add CTE, subquery, function/procedure, and overload completion tests that match A5’s advertised SQL input-assistance depth.CMPL-007: build a dialect-normalized explain-plan view, then add dialect-specific details for Oracle, DB2, SQL Server, MySQL, and PostgreSQL.EXEC/QA: add saved-run comparison and evidence export for repeated query validation, including multiple result sets.AI-005: keep Query Magics visible and auditable; consider comment directives only when they render as explicit commands before execution.IO: add spreadsheet paste/import previews, Excel-compatible export, and dummy-data generation without bypassing transaction review.ADV-003/004: connect table designer, ERD reverse generation, DDL generation, diagram export, and table-definition documents.SEC/AI: add workspace-level read-only mode, production DML/DDL confirmation, and AI-disabled policy switches.
RSQL Reference Notes
Last reviewed: 2026-06-26 JST.
Source: https://github.com/rust-dd/rsql
License Boundary
The public README currently links to LICENSE, but the LICENSE path returned
404 during review. Treat RSQL as a public README / behavior reference only until
compatible license terms are verified. Do not copy source code, UI wording,
assets, screenshots, or exact implementation from the repository.
Use this note to translate visible behavior and public performance claims into Irodori-owned requirements, benchmarks, and tests.
Useful Reference Points
- Large-result rendering: RSQL positions a canvas/WebGL grid as the primary
reason it can keep DOM cost flat on very large result sets. This belongs in
Irodori’s
PERF-001renderer spike as a benchmark lane against the current DOM virtual grid and possible WebGPU/canvas paths. - Server-side cursor pagination: RSQL describes PostgreSQL cursors, fixed-size pages, a small frontend page cache, and LRU eviction. Irodori already has bounded row virtualization and disk offload; the useful next comparison is a PostgreSQL cursor-backed result window for uncapped interactive browsing.
- Packed IPC: RSQL avoids nested JSON for large result pages by packing rows into separator-delimited strings. Irodori should benchmark this idea against current typed JSON, Arrow IPC, and any future binary page format before changing the command boundary.
- Dual query/metadata pools: RSQL separates user query traffic from metadata traffic. Irodori should evaluate the same separation for engines where schema refresh, completion, and object-browser calls can currently compete with a long user query.
- Rust-side result diffing: Pinned result comparison is useful for repeated query workflows. Irodori can implement its own diff model over current result pages or persisted spill handles.
- Record view for wide rows: A form-style row drawer/modal is a strong fit for Irodori’s wide-table UX and pairs with the existing history-detail drawer idea.
- PostgreSQL-specific admin views:
pg_stat_activity, table/index stats, locks, bloat, extensions, roles, ENUMs, settings, RLS policy editing, and LISTEN/NOTIFY are good PostgreSQL plugin/admin targets, not core cross-engine UI primitives. - EXPLAIN JSON visualization: Irodori already tracks explain entry points; the next useful bar is an interactive plan tree with cost, estimate-vs-actual, and timing emphasis.
- PostGIS map view: Geometry/geography detection plus a map renderer is a useful source-specific visualizer. Keep it behind result visualizer/plugin contracts so non-spatial engines do not inherit PostgreSQL-only assumptions.
- Production guard: Color-coded environments, read-only production mode, and explicit DML/DDL confirmation are worth bringing into Irodori’s safety model.
Not Directly Portable
- RSQL is PostgreSQL-first. Irodori must keep the adapter model broad enough for SQLite, MySQL/MariaDB, SQL Server, Oracle, warehouses, graph, document, KV, and time-series sources.
- RSQL’s simple-query text path is attractive for speed but loses typed values at the boundary. Irodori should preserve exact typed decoding where editing, filtering, import/export, or dialect behavior requires it.
- A separator-delimited IPC format must handle escaping, nulls, binary data, column metadata, backpressure, cancellation, and versioning before adoption.
- Canvas/WebGL grid adoption must include accessibility, selection/copy/editing, IME behavior, high-DPI behavior, print/export parity, and software fallback.
Candidate Backlog Follow-Ups
PERF-001: add an RSQL-inspired canvas/WebGL grid lane and compare scroll latency, CPU, memory, selection cost, and copy/edit behavior against DOM virtualization.EXEC-010/EXEC-008: prototype PostgreSQL cursor-backed result windows and run-to-file export over a shared page contract.TB/API: benchmark typed JSON vs packed text vs Arrow IPC for large result pages before changing generated command payloads.CMPL/BROWSE: split metadata traffic away from user query traffic where a connector supports independent pools or workers.ADV-004D: implement query-result graph/map visualizers through the same extension/result visualizer contract, not one-off PostgreSQL UI branches.EXEC-007: add a record-view drawer for wide rows before expanding inline edit complexity.
Support
Irodori Table is a development-preview, open-source database workbench. Use this page as the public support text for app stores, package managers, release pages, and the project site.
Public support channels
- Project site: https://hjosugi.github.io/irodori-docs/
- Documentation: https://hjosugi.github.io/irodori-docs/
- Releases: https://github.com/hjosugi/irodori-table/releases
- Issues: https://github.com/hjosugi/irodori-table/issues
- Security reports: follow the security policy
For suspected vulnerabilities, do not open a public issue with exploit details,
credentials, database dumps, connection strings, customer data, or private logs.
Use the private disclosure path described in SECURITY.md.
What to include in a bug report
Include enough detail to reproduce the behavior without exposing secrets:
- Irodori Table version and install channel.
- Operating system and architecture.
- Database engine and version, if relevant.
- The smallest query, schema shape, file, or workflow that reproduces the issue.
- A screenshot or redacted error message.
- Whether the issue happens in a clean workspace.
Do not include passwords, access tokens, private keys, database dumps, customer records, or unredacted production connection URLs.
Support scope
Supported project areas:
- install and startup problems;
- connection profile setup;
- SQL editor behavior, Vim mode, shortcuts, formatting, and execution;
- result grid display, export, and row inspection;
- schema metadata, completion, ERD, query plan, and migration/diff workflows;
- release artifacts, package-manager manifests, and updater behavior;
- extension SDK and connector-extension issues.
Out of scope for public issue support:
- recovering damaged production data;
- tuning private database infrastructure;
- debugging proprietary SQL or schemas that cannot be reduced to a public reproduction;
- account, tax, certificate, and signing issues for store maintainers.
Response expectations
Irodori Table is not yet a commercial support product. Public issues are handled on a best-effort basis. Security-sensitive reports and regressions in released installers take priority over feature requests.
Store listing support text
Short support statement:
Report bugs and request help through the GitHub issue tracker. Do not share credentials or private database data in public reports.
Japanese support statement:
不具合報告とサポート依頼は GitHub Issues で受け付けます。公開 Issue に認証情報や 非公開のデータベース内容を含めないでください。
Privacy Notice
Last updated: 2026-06-28
Irodori Table is a local-first desktop database workbench. This notice is written for public store listings and package-manager submissions. It is not legal advice; review it before using it as a formal privacy policy.
Summary
- Irodori Table does not include product analytics, advertising SDKs, or telemetry reporting in this repository.
- The app sends data to database servers, local files, proxy/SSH endpoints, and optional AI providers only when the user configures and uses those features.
- Connection details, editor content, query history, preferences, and generated metadata are handled locally by the desktop app unless the user explicitly exports, copies, opens, or sends them through a configured integration.
- Password-like values must not be pasted into public support requests. The app includes redaction helpers, but users remain responsible for reviewing shared diagnostics.
Data the app may process locally
Depending on the workflow, Irodori Table may process:
- database connection names, hostnames, ports, usernames, options, and transport settings;
- passwords, tokens, private keys, and proxy/SSH secrets entered by the user;
- SQL text, query parameters, query results, metadata, query plans, and edit previews;
- local files selected for import/export or SQLite-style local database access;
- UI preferences, themes, keybindings, result-grid settings, and query history;
- audit entries and diagnostic reports generated by the app.
Credentials and secrets
Connection passwords entered in normal connection profiles are treated as session-only UI input. Saved transport and proxy secrets use the app’s OS keychain-backed secret store where supported. Portable connection export paths redact password fields before writing shareable connection definitions.
Users should still treat local machines, exported diagnostics, screenshots, and query files as sensitive if they contain database names, table names, SQL text, business data, or credentials.
Network behavior
Irodori Table does not need a hosted Irodori account to run. Network access is created by user actions such as:
- connecting to configured database servers;
- connecting through configured SSH, SOCKS, or HTTP CONNECT transport paths;
- calling cloud database APIs or HTTP-based connectors;
- opening project links in a browser;
- using optional AI generation or explanation providers such as a local Ollama server or an OpenAI-compatible HTTP endpoint configured by the user;
- downloading releases or package-manager updates from public release channels.
Third-party database providers, AI providers, proxy services, operating-system keychains, and package managers process data under their own terms.
Logs and diagnostics
The app includes privacy mode, redaction helpers, and redacted audit export support. These features are designed to reduce accidental disclosure, not to guarantee that every private value has been removed from arbitrary user content. Review any diagnostics before sharing them.
Data deletion
Users can remove local app data by deleting local Irodori Table preferences,
workspaces, generated cache files, and any saved OS keychain entries for the
irodori-table service. Package managers may keep their own install caches.
Contact
Use the public support channels in support.md. For suspected security issues, follow the security policy.
Disclaimer
Irodori Table is a development-preview, open-source database workbench. This page provides public disclaimer text for release pages, app stores, package manager submissions, and support references.
Development preview
The application is pre-1.0. Features, file formats, extension APIs, and supported database behavior may change. Preview builds can contain defects and incomplete connectors.
Database operations
Database clients can run destructive commands. Review generated SQL, edit previews, migration plans, import/export settings, and target connections before executing them. Use backups, transactions, read-only accounts, staging databases, and least-privilege credentials when working with important data.
Irodori Table does not guarantee recovery from accidental data loss, incorrect queries, migration mistakes, permission mistakes, network failures, or third-party service behavior.
AI-assisted features
AI-assisted SQL generation and explanation features can produce incomplete, incorrect, insecure, or inefficient output. Treat generated SQL and explanations as drafts. Verify syntax, permissions, query plans, and business impact before running generated statements.
If an external AI provider is configured, prompts and related schema/query context may be sent to that provider according to the user’s configuration and the provider’s own terms.
Third-party systems
Irodori Table connects to database engines, cloud APIs, SSH/proxy transports, OS keychains, package managers, and optional model providers. Those systems are owned and operated independently. Availability, compatibility, pricing, data handling, and access controls are governed by the relevant third party.
License and warranty
Project-authored code is licensed under MIT OR 0BSD unless a file says
otherwise. The software is provided without warranty. See the
license for the
controlling license text.
Licensing
Irodori Table’s own code is dual-licensed under MIT OR 0BSD.
The intent is simple: anyone can use, copy, fork, sell, rewrite, embed, or compete with Irodori Table without asking for permission. Users can choose the familiar MIT license or the almost-no-conditions 0BSD license.
Why Dual License
- MIT is familiar to companies, package managers, and open-source contributors.
- 0BSD preserves the project’s “fully free to copy” goal.
- Both avoid copyleft obligations for downstream users.
- The SPDX expression
MIT OR 0BSDworks well for npm and Cargo metadata. - Official extension examples and templates can be reused under either path.
What This Does Not Mean
- Dependencies keep their own licenses.
- Extensions keep their own licenses unless their author chooses
MIT OR 0BSD. - Reference repositories under
.irodori-local/ref/are not part of Irodori Table and keep their original licenses. - GPL/AGPL code can be studied, but it must not be copied into the permissive core unless the project intentionally creates a separate license boundary.
- Commercial or proprietary reference code is off-limits unless we have explicit rights.
- Third-party adapted code keeps its original obligations; the
MIT OR 0BSDchoice applies to Irodori-authored code.
Default Policy
- New Irodori-authored code:
MIT OR 0BSD. - Official examples and extension templates:
MIT OR 0BSD. - Third-party copied/adapted code: avoid when possible; when used, record the source, license, and attribution requirements.
- Core app, extension API, and SDK packages should remain permissive enough that downstream users can build anything on top.
Compatibility Classes
- Allowed by default:
MIT,0BSD,BSD-2-Clause,BSD-3-Clause,ISC,Apache-2.0,Unlicense,CC0-1.0, and similarly permissive licenses. - Allowed with asset-specific review:
MPL-2.0,EPL-2.0,CDDL, Creative Commons attribution licenses, and font licenses such asOFL-1.1. - Dependency-only review required: native drivers, parser generators, grammar packages, crypto/TLS libraries, and packages that bundle binary artifacts.
- Blocked for the permissive core unless an explicit separate license boundary is approved:
GPL,LGPL,AGPL, commercial-only terms, source-available licenses that restrict use or competition, no-license code, and unclear provenance.
Asset Rules
| Asset type | Allowed | Needs review | Blocked in the permissive core |
|---|---|---|---|
| Rust crates and npm packages | Permissive licenses listed above, declared in package metadata | Dual-licensed packages, native/binary packages, unusual patent terms | GPL/AGPL/copyleft packages that would affect the core distribution |
| Official extension templates and examples | Irodori-authored MIT OR 0BSD | Third-party sample code with attribution | Code copied from incompatible products or commercial examples |
| Themes | Original themes or permissive VS Code themes with attribution | Marketplace themes with mixed assets or unclear bundled licenses | Proprietary themes, copied product themes, GPL/AGPL themes for bundled distribution |
| Snippets and query templates | Original snippets, public-domain examples, permissive examples with attribution | Vendor docs examples when terms are unclear | Copied paid-course, book, commercial-product, or incompatible OSS snippets |
| Icons, images, and logos | Original assets, permissive icon sets, project-owned marks | CC-BY assets with required attribution, trademarked database logos used only as nominative references | Competitor icons, proprietary screenshots, unlicensed web images |
| Fonts | System fonts, OFL-1.1, permissive fonts | Font licenses with embedding or naming restrictions | Commercial fonts without redistribution rights |
| Tree-sitter grammars and language data | Permissive grammars with recorded license | Mixed-license grammars or generated artifacts | GPL/AGPL grammars bundled into the core |
| Database drivers and native clients | Permissive pure-Rust or clearly redistributable drivers | Vendor clients with platform packaging terms | Drivers or SDKs that forbid redistribution, competition, or reverse engineering |
| Sample data and fixtures | Original data, synthetic data, public-domain datasets | Public datasets with attribution/share requirements | Production data, personal data, unclear-license dumps |
When in doubt, do not vendor or copy the asset. Link the public source, record the license question in the PR, and implement the Irodori behavior independently.
Path to 1.0
1.0 is the excellent, stable core — not every roadmap item. The strategic call is to ship a polished cross-platform SQL GUI for the core SQL engines and explicitly defer the exotic surfaces. Current version: 0.6.0.
P0 — blockers (must do for 1.0)
- Declare the supported-engine line. 1.0 = PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle as supported; everything else (lakehouse, graph, vector, time-series, the long in-progress list) is experimental. Without this, 1.0 never closes.
- Stabilize the build.
cargo buildgreen on default features (the DB-connector feature refactor is mid-flight and only builds via--features legacy-connectors). (Done: the dev[patch]is removed andirodori-sqlv0.3.0 is cut — the workspace now consumes it from thev0.3.0tag.) - Core data workflows (Phase 6): schema compare + migration preview (engine
already exists in
irodori-sql/schema.rs— mostly wiring), editable results + table designer + index/constraint UI, data compare + safe bulk edit. - UI / theme completeness: finish
THEME-001b(no hardcoded colors — all theme variables) +THEME-002(theme import/save/switch). (In progress: the AI dialog + terminal were converted to theme variables.) - Release mechanics: code signing/notarization (macOS/Windows), the Tauri in-app updater (see distribution.md), and green CI (typegen drift, unit, browser smoke, Rust tests, security).
P1 — strongly wanted
PERF-001: settle the result-grid rendering path; prove 1M-row smoothness.- Workspace basics polish (tab CRUD, history search, saved queries, per-tab connection binding).
- Git graph hardening (commit actions, branch ops).
- AI generation stays opt-in + audited (it’s optional, never required).
Defer to post-1.0
Lakehouse/Iceberg, Snowflake full-auth, Neo4j/graph, InfluxDB/time-series, vector DBs, the headless API as a shipped product, the extension registry (local SDK is enough), team/workspace sync — and keep the new integrated terminal and local AI generation behind feature flags so they don’t gate 1.0.
Recommended next step
Schema compare + migration preview (highest functional leverage; the diff/migration
engine already exists in irodori-sql), then build-stabilization + theme
completeness.
Appendix: Internal Runbooks
These pages are useful for maintainers and release planning, but they are not part of the first-read user path.
- External DB contract & verification
- Data verification diff
- Data-source content audit
- Distribution and updates
- Store and package registration
- Private store runbook template
- Parallel agent architecture
Engine Cheatsheets
One page per database that answers, fast: how do I connect from Irodori, what is
the query model, and what are the per-engine quirks I will trip on. These are the
human-facing, copy-pasteable companion to the deeper docs/engine-syntax-reference.md
(driver/decoding internals) and docs/data-source-support-status.md (coverage).
Each cheatsheet is meant to be generated from the local knowledge inputs in
irodori-table (knowledge/cheatsheets/*.json plus the knowledge DB). Until a
page is generated, it may be hand-seeded and marked <!-- seed -->. Generator
ownership and drift rules are tracked in
repository-boundaries.md.
Index
| Cheatsheet | Engine(s) covered | Status |
|---|---|---|
| neo4j.md | Neo4j (graph, Bolt/Cypher); Memgraph notes | Seed (flagship) |
| postgres.md | PostgreSQL (+ Cockroach/Yugabyte/Redshift/Timescale/Neon) | Generated (knowledge/cheatsheets/postgres.json) |
| questdb.md | QuestDB (Postgres wire + time-series SQL extensions) | Seed |
| mysql.md | MySQL / MariaDB / TiDB | Planned |
| sqlite.md | SQLite | Planned |
| sqlserver.md | SQL Server | Planned |
| duckdb.md | DuckDB | Planned |
| mongodb.md | MongoDB | Planned |
New cheatsheets are added only for engines that are at least Wired in
docs/data-source-support-status.md. An engine that is “Recognized, no connector”
or “Not registered” gets a row in the support-status doc, not a cheatsheet, until
it can actually connect.
Page format (the template every cheatsheet follows)
Keep sections in this order so the generator can produce them deterministically and so readers build muscle memory:
- At a glance — wire/driver, default port, query language, Irodori support status, and a one-line “what makes this engine different”.
- Connect — Irodori connection fields and the raw URL/DSN form, with a minimal working example.
- Query model — what you type, what comes back, row cap behavior.
- Essential statements — a tight, runnable set of the 80%-case queries.
- Introspection — how to list objects the way Irodori’s object browser does.
- Irodori-specific behavior — mapping/quirks unique to how this app handles the engine (decoding, object-browser mapping, what’s not implemented yet).
- Gotchas — the small number of things that actually bite people.
- Sources — the
knowledge/sources.jsonids the page was generated from.
The Sources footer is load-bearing: it ties each page back to the official docs in the knowledge registry so a refresh can detect when a page is stale.
PostgreSQL Cheatsheet
At a glance
| Wire / driver | Postgres / sqlx PgPool |
| Adapter | apps/desktop/src-tauri/src/db/postgres.rs |
| Default port | 5432 |
| Query language | SQL (PostgreSQL dialect) |
| Irodori status | Verified — see docs/data-source-support-status.md |
| What’s different | The wire-compatible engines (CockroachDB, YugabyteDB, Redshift, TimescaleDB, Neon) reuse this exact path; only the default port and a few catalog quirks differ. |
Connect
Irodori accepts either a raw url/DSN or structured fields.
| Field | Example |
|---|---|
url | postgres://user:pass@host:5432/db |
| host / port | 127.0.0.1 / 5432 |
| user / password | postgres / postgres |
| database | postgres |
Wire-compatible variants change only the port: CockroachDB 26257
(?sslmode=disable for insecure), YugabyteDB YSQL 5433, Redshift 5439.
Query model
- You type SQL; rows come back as a table.
- Rows are capped at
max_rows(default 10,000) and flaggedtruncated: truewhen more remain. AddLIMITfor large scans. - Version:
select version(). - Multiple statements return multiple result sets.
Essential statements
-- Read with paging
SELECT id, name FROM customers ORDER BY id LIMIT 50 OFFSET 0;
-- Parameters use $1, $2 (positional)
SELECT * FROM orders WHERE tier = $1 AND created_at >= $2;
-- Upsert
INSERT INTO customers (id, name) VALUES (1, 'Ada')
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name;
-- JSON / JSONB
SELECT data->>'email' AS email FROM events WHERE data @> '{"tier":"gold"}';
-- CTE
WITH recent AS (SELECT * FROM orders WHERE created_at > now() - interval '7 days')
SELECT tier, count(*) FROM recent GROUP BY tier;
- Identifier quoting: ANSI double quotes —
"My Col"; escape"by doubling. - Paging:
LIMIT n OFFSET m.
Introspection
-- Schemas, tables, columns via the standard catalog
SELECT table_schema, table_name FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog','information_schema');
SELECT column_name, data_type FROM information_schema.columns
WHERE table_name = 'customers';
-- psql-style shortcuts (also work through Irodori's editor)
SELECT version();
Irodori’s object browser reads schemas, tables, views, columns, indexes, and constraints through the Postgres information-schema metamodel.
Irodori-specific behavior
- Decoding:
NUMERIC→string (exact, viaBigDecimal),TIMESTAMPTZ→RFC3339,TIMESTAMP/DATE/TIME→string,JSON/JSONB→object,UUID→string,BYTEA→\xHEX, bool/ints/floats native. - Arrays decode best-effort to text today (rich array decode is a follow-up).
- CockroachDB omits some
OID-typed system columns that tools expect. - The deep driver/decoding reference is
docs/engine-syntax-reference.md.
Gotchas
- Use positional parameters (
$1) — not string interpolation. now()is transaction-time; useclock_timestamp()for wall-clock.- Wire-compatible engines share this adapter, so a Postgres-only feature may behave differently on CockroachDB/Yugabyte/Redshift — check the per-engine quirks.
Sources
Generated from knowledge/sources.json:
postgres-docs-current— https://www.postgresql.org/docs/current/postgres-release-notes-current— https://www.postgresql.org/docs/current/release.html
Neo4j Cheatsheet
At a glance
| Wire / driver | Bolt / neo4rs (pure Rust) |
| Adapter | apps/desktop/src-tauri/src/db/neo4j.rs |
| Default port | 7687 (Bolt) |
| Query language | Cypher (not SQL) |
| Irodori status | Wired (graph) — see docs/data-source-support-status.md |
| What’s different | Data is nodes and relationships, not rows. You query patterns with Cypher and get back records of nodes/relationships/scalars. |
Connect
Irodori accepts either a raw url or structured fields. Defaults match the
adapter: host 127.0.0.1, port 7687, user neo4j, database neo4j, empty
password.
| Field | Example | Notes |
|---|---|---|
url | bolt://127.0.0.1:7687 | Overrides host/port. Use neo4j:// for routing/cluster, bolt+s:// / neo4j+s:// for TLS. |
| host / port | 127.0.0.1 / 7687 | Used only when url is empty; adapter builds bolt://host:port. |
| user | neo4j | |
| password | password | |
| database | neo4j | The Neo4j database name (4.x+ multi-db). |
Minimal raw form: bolt://neo4j:password@127.0.0.1:7687 (database selected
separately, defaults to neo4j).
Query model
- You type Cypher; Irodori runs it through
Graph::execute. - Results become a table: columns = the ordered union of
RETURNkeys across records; each record fills known columns, missing keys →null. - Node / relationship / path values render as JSON cells (their properties).
- Rows are capped at
max_rows(default 10,000); the result is flaggedtruncated: truewhen more remain. Add an explicitLIMITfor large graphs. - Version: Irodori reads it via
CALL dbms.components().
Essential statements
-- Read a pattern
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.released >= 2000
RETURN p.name AS actor, m.title AS movie
ORDER BY m.released DESC
LIMIT 25;
-- Parameters (preferred over string interpolation)
MATCH (p:Person {name: $name}) RETURN p;
-- Create / upsert
CREATE (p:Person {name: 'Ada', born: 1815});
MERGE (p:Person {name: 'Ada'}) -- match-or-create on the key
ON CREATE SET p.born = 1815
ON MATCH SET p.seen = timestamp();
-- Relate
MATCH (a:Person {name:'Ada'}), (m:Movie {title:'Analytics'})
MERGE (a)-[r:ACTED_IN {role:'self'}]->(m);
-- Aggregate / collect
MATCH (p:Person)-[:ACTED_IN]->(m)
RETURN p.name, count(m) AS films, collect(m.title) AS titles
ORDER BY films DESC;
-- Pipe with WITH, expand lists with UNWIND
UNWIND [1,2,3] AS n RETURN n*n AS square;
-- Variable-length path
MATCH path = (a:Person {name:'Ada'})-[:KNOWS*1..3]-(b:Person)
RETURN b.name, length(path) AS hops;
-- Delete safely (detach removes attached relationships)
MATCH (p:Person {name:'Ada'}) DETACH DELETE p;
Clause order to memorize: MATCH → WHERE → WITH → RETURN → ORDER BY →
SKIP → LIMIT. WITH is the pipe between query parts (it also gates WHERE
after aggregation).
Introspection
This is exactly what Irodori’s object browser runs against Neo4j:
CALL db.labels() YIELD label RETURN label; -- node labels
CALL db.relationshipTypes() YIELD relationshipType RETURN relationshipType; -- rel types
CALL db.propertyKeys() YIELD propertyKey RETURN propertyKey; -- property keys
SHOW INDEXES; -- indexes (4.x+)
SHOW CONSTRAINTS; -- constraints (4.x+)
CALL dbms.components(); -- server name / version / edition
Indexes & constraints you will create often:
CREATE INDEX person_name IF NOT EXISTS FOR (p:Person) ON (p.name);
CREATE CONSTRAINT person_name_unique IF NOT EXISTS
FOR (p:Person) REQUIRE p.name IS UNIQUE;
Irodori-specific behavior
- Object browser mapping (
neo4j.rs::metadata): node labels are shown as “tables” and relationship types as “views”. Their “columns” are the property keys, sampled withMATCH (n:\Label`) UNWIND keys(n) AS key RETURN DISTINCT key LIMIT 100`. This is a sampling pass, so a property that only appears on a few nodes can be missed — treat the column list as representative, not exhaustive. - Results are tabular today. Node/relationship records show as JSON property
cells. A query-result graph visualization is a planned shared capability
(P1, see
docs/data-source-coverage-strategy.md→ Graph), not yet in the UI. - No SQL. Engines like advanced filters / inline editing that assume relational
semantics do not apply; use Cypher
SET/MERGE/DELETE.
Gotchas
- Use parameters (
$name) instead of string-building queries — safer and lets the planner cache the plan. MATCH ... DELETEfails if the node still has relationships; useDETACH DELETE.- Backtick labels/types with special characters:
:`Order Line`. MERGEmatches on the whole pattern —MERGE (p:Person {name:'Ada', born:1815})with a differentborncreates a second node. Merge on the key, thenSET.- Bolt over TLS needs the
+sscheme (bolt+s:///neo4j+s://).
Related: Memgraph
Memgraph speaks Bolt + Cypher and is in the DbEngine enum (memgraph) but is
currently “recognized, no connector” — most of this page applies once it is
routed through the Neo4j/Bolt adapter and verified.
Sources
Generated from knowledge/sources.json:
neo4j-cypher-manual— https://neo4j.com/docs/cypher-manual/current/neo4j-browser-docs— https://neo4j.com/docs/browser/
QuestDB Cheatsheet
At a glance
| Wire / driver | PostgreSQL wire protocol / sqlx PgPool |
| Adapter | apps/desktop/src-tauri/src/db/postgres.rs |
| Default port | 8812 |
| Query language | SQL with QuestDB time-series extensions |
| Irodori status | Wired through the Postgres-compatible path - see data-source-support-status |
| What’s different | Querying is SQL-like, but the high-value features are designated timestamps, SAMPLE BY, LATEST ON, ASOF JOIN, TOLERANCE, and metadata functions such as tables(). |
Connect
Irodori accepts either a raw url/DSN or structured fields. QuestDB’s
PostgreSQL wire endpoint defaults to port 8812.
| Field | Example | Notes |
|---|---|---|
url | postgres://admin:quest@127.0.0.1:8812/qdb | Uses the Postgres-compatible driver path. |
| host / port | 127.0.0.1 / 8812 | Used only when url is empty. |
| user / password | admin / quest | Adjust for your QuestDB deployment. |
| database | qdb | Common default for QuestDB PGWire connections. |
Query model
- You type SQL and Irodori renders rows as a normal result table.
- Multiple statements use the same execution path as Postgres-compatible engines.
- For time-series queries, prefer tables with a designated timestamp. It is
the timestamp QuestDB uses for
SAMPLE BY,LATEST ON, and time-series joins. - Add explicit time predicates early. Common QuestDB examples use
timestamp IN '2026-01-01',BETWEEN, or boundedFROM ... TOinsideSAMPLE BY.
Essential statements
-- Recent rows
SELECT *
FROM trades
WHERE timestamp IN '2026-01-01'
ORDER BY timestamp DESC
LIMIT 100;
-- Downsample by a fixed interval
SELECT timestamp, symbol, avg(price) AS avg_price, count() AS rows
FROM trades
WHERE timestamp IN '2026-01-01'
SAMPLE BY 1h;
-- Downsample with explicit output range and fill
SELECT timestamp, avg(price) AS avg_price
FROM trades
WHERE timestamp BETWEEN '2026-01-01T00:00:00Z' AND '2026-01-02T00:00:00Z'
SAMPLE BY 5m
FROM '2026-01-01T00:00:00Z' TO '2026-01-02T00:00:00Z'
FILL(PREV)
ALIGN TO CALENDAR TIME ZONE 'UTC';
-- Latest row per series key
SELECT symbol, timestamp, price
FROM trades
WHERE timestamp IN '2026-01-01'
LATEST ON timestamp PARTITION BY symbol;
-- As-of join: each left row gets the nearest right row at or before its time
SELECT t.timestamp, t.symbol, t.price, q.bid_price, q.ask_price
FROM trades t
ASOF JOIN quotes q ON (symbol);
-- As-of join with a bounded lookback window
SELECT t.timestamp, t.symbol, t.price, q.bid_price
FROM trades t
ASOF JOIN quotes q ON (symbol) TOLERANCE 50T
WHERE t.timestamp IN '2026-01-01';
SAMPLE BY
Shape to memorize:
SELECT timestamp_column, aggregate(...)
FROM table_name
[WHERE ...]
SAMPLE BY 5m
[FROM 'start' TO 'end']
[FILL(NULL | PREV | LINEAR | constant)]
[ALIGN TO CALENDAR [TIME ZONE 'UTC'] [WITH OFFSET '...']
| ALIGN TO FIRST OBSERVATION];
Operational notes:
SAMPLE BYneeds a designated timestamp column.- Use
FROM ... TOwhen you want missing intervals to appear in the result. FILLdecides how empty buckets are represented. Common choices areNULL,PREV,LINEAR, or a constant.FILLcomes beforeALIGN.- Calendar alignment is the default mental model for reporting buckets; first observation alignment is useful when the first row should define bucket edges.
ASOF JOIN
Common forms:
-- Keyless: nearest right timestamp at or before the left timestamp
SELECT *
FROM left_table
ASOF JOIN right_table;
-- Keyed: match both time and one or more series keys
SELECT *
FROM left_table l
ASOF JOIN right_table r ON (symbol);
-- Limit stale matches
SELECT *
FROM left_table l
ASOF JOIN right_table r ON (symbol) TOLERANCE 1s;
Operational notes:
- The time comparison is implicit: QuestDB uses designated timestamps from the left and right inputs.
- Add
ON (...)when a join must match by series key, such assymbol. TOLERANCElimits how far back QuestDB can look in the right-side input.- If a subquery should join on a non-designated timestamp, order it by that timestamp so QuestDB can use it as the time axis.
LATEST ON
SELECT *
FROM balances
LATEST ON ts PARTITION BY cust_id;
SELECT cust_id, balance_ccy, balance
FROM balances
LATEST ON ts PARTITION BY cust_id, balance_ccy;
Use LATEST ON for “most recent row per key”. The order of WHERE and
LATEST ON matters. Without parentheses, a WHERE before LATEST ON filters
first and then picks the latest row. Wrap a LATEST ON query in parentheses when
you want to pick latest first and filter afterward.
Introspection
-- Table inventory, row counts, timestamp range, WAL state
SELECT table_name,
table_row_count,
table_min_timestamp,
table_max_timestamp,
walEnabled,
wal_pending_row_count
FROM tables()
ORDER BY table_max_timestamp DESC
LIMIT 20;
-- Partitions and disk footprint
SELECT *
FROM table_partitions('trades')
ORDER BY minTimestamp DESC;
SELECT size_pretty(sum(diskSize)) AS disk_size
FROM table_partitions('trades');
-- Active queries
SELECT *
FROM query_activity();
-- Materialized views
SELECT *
FROM materialized_views();
Irodori-specific behavior
- QuestDB is exposed as the
questdbengine but uses the same Postgres-wire execution path aspostgres.rs. - The SQL editor completion is QuestDB-aware for
SAMPLE BY,LATEST ON,ASOF JOIN,TOLERANCE,FILL, and metadata helpers. - Default snippets include
sampleby,samplebyfill,lateston,asofjoin,asofjointol, andqdbmeta. - Generic result handling still applies: rows render as tables, and large result
sets should use explicit
LIMITor bounded time predicates.
Gotchas
- Do not treat QuestDB as “just Postgres”. Query syntax is compatible enough for the wire protocol, but time-series SQL extensions are QuestDB-specific.
SAMPLE BYandLATEST ONwork best with a designated timestamp. If you are querying imported or derived data without one, use subqueries carefully.FILL(NONE)is exclusive; do not mix it with other fill strategies.- For
ASOF JOIN, forgettingON (symbol)can silently join across different series because only time is considered. - Use
TOLERANCEwhen stale right-side values would be dangerous. - Prefer partition/time-bounded reads in production. Unbounded scans over hot time-series tables can be very large.
Sources
- QuestDB
SAMPLE BYdocs - https://questdb.com/docs/query/sql/sample-by/ - QuestDB
ASOF JOINdocs - https://questdb.com/docs/query/sql/asof-join/ - QuestDB
LATEST ONdocs - https://questdb.com/docs/query/sql/latest-on/ - QuestDB metadata functions - https://questdb.com/docs/query/functions/meta/
- Irodori support matrix - data-source-support-status
0000 - ADR Process
Status: accepted
Context
Irodori docs include architecture decisions that explain durable product and
implementation choices. The series started at 0001, but contributors need a
stable place that explains how new decisions are named, scoped, and updated.
Decision
Use Architecture Decision Records under src/adr/ for decisions that affect
public architecture, repo boundaries, extension contracts, release policy, or
long-lived developer workflow.
ADR files follow this naming convention:
NNNN-short-title.md
Use four digits, keep titles lowercase with hyphens, and never renumber existing ADRs. Each ADR should include:
- status: proposed, accepted, superseded, or rejected;
- context: the problem or constraint that forced a decision;
- decision: the chosen rule or direction;
- consequences: tradeoffs and follow-up work.
When a decision changes, add a new ADR and mark the old one as superseded with a link to the replacement. Small clarifications can be edited in place when they do not change the decision.
Consequences
- Contributors have a documented process before adding
0002and later ADRs. - Historical decisions stay stable and linkable.
- Public docs can explain why the implementation is shaped a certain way without mixing durable decisions into transient roadmap pages.
ADR 0001 — SQL Editor Stack (engine · highlighting · formatter)
- Status: Accepted implementation direction; last reconciled 2026-06-25 JST.
- Backlog: decides EDIT-001; gates EDIT-002 (highlighting) and EDIT-008 (formatter). Related: THEME-001, EDIT-005 (Vim), EDIT-007 (SQL-aware selection), completion-and-ai-strategy.md.
- Current implementation snapshot: CM6 editor exists,
sql-formatteris wired, and desktop schema-aware completion is smoke-tested from live metadata. The shared completion contract for local API and future hosts remains open.
Context
At the time this ADR was opened, the query editor was a plain <textarea> in
apps/desktop/src/App.tsx with hand-rolled SQL helpers (statementDelimiters,
dollarTagAt, compactSql). The first CM6 implementation now exists. The
ADR records the path to production-quality dialect-aware syntax highlighting
and SQL formatting, while preserving room for deterministic completion, Vim,
multi-cursor, and large-file performance.
Constraints from existing docs:
- Multi-dialect, multi-language mandate. Not just SQL: Cypher, time-series SQL/native, document/KV, search DSLs, warehouse dialects (
completion-and-ai-strategy.md). - Host portability. A future move off the Tauri WebView to a native Rust GUI must not be foreclosed; keep the semantic layer and completion contracts portable across hosts.
- License. Core is
MIT OR 0BSD; every editor dependency must be permissive and compatible. - “Tree-sitter where strong, dialect fallback.” EDIT-002 already commits to this wording; SQL tree-sitter grammar quality varies by dialect.
Decision
- Editor host → CodeMirror 6 (MIT).
- Highlighting → two layers: CM6 Lezer (
@codemirror/lang-sql) as the paint layer now;web-tree-sitter(WASM) as the semantic/parse layer (completion context, outline, SQL-aware selection, folding). - Formatter →
sql-formatterv15 (MIT), pluggable and dialect-mapped; a CST-based formatter is a later v2.
Reference-project evidence (verified 2026-06-22)
| Client | Editor | License posture | Takeaway |
|---|---|---|---|
| Beekeeper Studio | CodeMirror 6 (incl. CM6 Vim keymap) | GPL → behavior only | The OSS daily-driver baseline runs CM6 + Vim. |
| Outerbase / LibSQL Studio | CodeMirror 6 + @codemirror/lang-sql (dialect select, function-hint, autocomplete) | AGPL → behavior only | Closest web-DB-GUI peer; CM6 carries dialect highlighting + completion. |
| Zequel | Monaco | Elastic → behavior only | Monaco is viable but heavier; the outlier. |
| DBeaver / DataGrip | Native per-dialect parsers (Eclipse / IntelliJ PSI) | DBeaver Apache-2.0 (adaptable) | Informs the per-engine SQLDialect concept, not the web host. |
→ Among web/Electron DB clients — the closest architectural peers to a Tauri WebView — CodeMirror 6 is the dominant, proven choice.
Why CodeMirror 6 over Monaco / native
| Criterion | CodeMirror 6 | Monaco | Native + tree-sitter only |
|---|---|---|---|
| Bundle / startup in a WebView | Small, modular, tree-shakeable | Large (~MBs), worker-based | n/a (no web) |
| Deep completion customization | First-class extension API | Possible but opinionated | Full control, all DIY |
| Vim quality | @codemirror/vim, proven by Beekeeper | Available, less idiomatic | DIY |
| Dialect highlighting out of the box | @codemirror/lang-sql: PG/MySQL/MariaDB/MSSQL/SQLite | TextMate/Monarch, more wiring | DIY |
| “Perfect quickly” | Best | Medium | Worst |
| Future native-host move | Re-host needed | Re-host needed | Already native |
Net: CM6 is the fastest route to a production-quality editor now, and the semantic layer (below) is what we carry across a possible native move — not the host.
Why tree-sitter as the semantic layer
Yes — but as parse-context, not the day-1 paint layer.
- The CM6 Lezer grammar paints instantly and is themeable today. The SQL tree-sitter ecosystem is fragmented per dialect (DerekStride/tree-sitter-sql is MySQL-leaning;
tree-sitter-postgresis generated from the PG18 Bison grammar; BigQuery is a separate grammar; Oracle PL/SQL coverage is weak). There is no single solid multi-dialect SQL tree-sitter grammar, so painting from tree-sitter now would be slower to perfect and patchy — contradicting “perfect quickly.” - Tree-sitter earns its place for incremental CST → semantic features: completion scope (aliases, CTEs, recursive CTEs, derived tables, subqueries, lateral joins), document outline, SQL-aware selection expansion (token → expression → clause → statement, EDIT-007), and folding. Its uniform grammar interface also extends to Cypher and other non-SQL languages the strategy targets.
- Portability dividend:
web-tree-sitterruns in the WebView today and the same grammars run in native Rust later → this is the layer that survives a host move. - Integration boundary: keep tree-sitter decoupled from CM painting initially. Only bridge tree-sitter captures into CM highlighting later if it clearly beats Lezer for a given dialect (this realizes EDIT-002’s “Tree-sitter where the grammar is solid, with a dialect fallback”).
Formatter detail (EDIT-008)
sql-formatterv15.8.1 (MIT, ~500 dependents) covers Postgres, MySQL, MariaDB, TiDB, SQLite (sql), T-SQL, PL/SQL, Redshift, DuckDB, ClickHouse, Snowflake, Spark, Trino, BigQuery, DB2 — a near-exact match to Irodori’s engine list. MapDbEngine → sql-formatter language.- Wire a format hook + “Format SQL” command; formatter choice is configurable (EDIT-008 requires this). Comment-toggle and bracket-matching ride CM6 built-ins.
- v2: a CST/tree-sitter-driven formatter for dialect-perfect output where
sql-formatterfalls short (e.g. exotic PL/SQL, vendor extensions).
Consequences / risks
- Frontend deps: CM6 packages and
sql-formatterare part of the current editor path;web-tree-sitter+ per-dialect grammar.wasmremain pending for the semantic layer. Benchmark bundle size and large-file responsiveness (EDIT-001 done-when). - THEME-001 is the real prerequisite for EDIT-002: map Lezer highlight tags (and, later, tree-sitter captures) into one normalized theme model — do not assume TextMate-only scopes.
- Verify each per-dialect tree-sitter grammar’s license individually before bundling (keep the core
MIT OR 0BSD-clean).
Rejected
- Monaco — heavier bundle, worker model, harder deep-customization of completion/Vim; better suited to full IDEs.
- Native / tree-sitter-only editor now — rebuilding text editing, IME, accessibility, and selection from scratch is too slow to “perfect quickly”; revisit only if/when the host goes native.
- Keep
<textarea>+ highlight overlay — does not scale to highlighting + completion + Vim + multi-cursor.
First steps (prototype = EDIT-001 done-when)
-
✅ Done — CM6 editor in
apps/desktop(src/SqlEditor.tsx),@codemirror/lang-sqldialect bound to the activeDbEnginevia a Compartment;basicSetupbrings line numbers, bracket matching, history, active-line, and keyword autocomplete.tscclean,vite buildgreen. -
✅ Done —
sql-formatterwired behind the toolbar “Format SQL” action, dialect-mapped per engine. -
⏳ Partial — Vim mode smoke is covered in browser Playwright (
@replit/codemirror-vimtoggle + CM Vim panel). Remaining: large-file responsiveness (5–20k lines) and a focused Vim behavior suite for motions/operators/registers; full Tauri runtime smoke still needs a Tauri runner. -
⏳ Pending —
web-tree-sitter+ one grammar (Postgres) as a non-painting outline/selection spike to de-risk the semantic layer. -
⏳ Open / revalidate — schema-aware completion: product status should be treated as keyword/basic autocomplete only until active
DatabaseMetadataproduces user-facing schema/table/column suggestions through a tested shared completion contract. That contract should feed CM6 now and future hosts later; tree-sitter scope resolution layers on after the schema/table/column baseline is proven.
Bundle note: CM6 adds ~ to the client bundle (961 kB raw / 293 kB gzip total with React + lucide). Acceptable for a desktop shell; revisit code-splitting if it grows.