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 publishes desktop packages from GitHub Releases. The release state checked for this guide is:
- latest stable GitHub Release:
v0.8.5, published on 2026-07-30; - latest lightweight prerelease:
v0.8.12, published on 2026-08-20.
https://github.com/irodori-table/irodori-table/releases
Stable releases publish Linux, universal macOS, and Windows packages. The
current stable release also includes signed Tauri updater metadata, although
its macOS and Windows installers are not platform-signed and may trigger
Gatekeeper or SmartScreen warnings. Lightweight prereleases publish Linux
AppImage, .deb, and .rpm packages only. cargo install does not install the
desktop application; it is only for the separate headless irodori-server.
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: portable AppImage
mkdir -p "$HOME/Applications"
gh release download --repo irodori-table/irodori-table --pattern "*.AppImage" --dir "$HOME/Applications"
chmod +x "$HOME/Applications"/Irodori*.AppImage
"$HOME/Applications"/Irodori*.AppImage
To test the newest lightweight prerelease instead of the latest stable release, pass the tag explicitly:
gh release download v0.8.12 --repo irodori-table/irodori-table --pattern "*.AppImage" --dir "$HOME/Applications"
Downloads by OS
| OS | Recommended asset | Notes |
|---|---|---|
| Linux | .AppImage | Stable and lightweight releases also provide .deb and .rpm packages. |
| Windows | setup .exe | The stable release also provides an .msi; current installers are unsigned. |
| macOS | universal .dmg | The current package is unsigned and may trigger Gatekeeper warnings. |
Windows
Download the setup .exe or .msi from the latest stable release. The current
installers are unsigned, so verify that the URL is under
github.com/irodori-table/irodori-table/releases before accepting a
SmartScreen warning. For a source build, use the
Windows development guide.
macOS
Download the universal .dmg from the latest stable release. The current disk
image is unsigned and not notarized, so macOS may show a Gatekeeper warning.
For a source build, use the macOS development guide.
Linux
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 the foundation tag used by the current desktop workspace:
cargo install --git https://github.com/irodori-table/irodori-kit --tag v0.7.5 --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/irodori-table/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:
task setup
task doctor
Run the desktop app
Start the Tauri development shell:
npm --prefix apps/desktop run tauri -- dev
Or, when make is available:
task 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/irodori-table/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
task setup
task 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
task desktop-dev
task 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
task desktop-format-check
task desktop-lint
task desktop-test
task 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/irodori-table/irodori-samples ../irodori-samples
task db-up DB=postgres
task 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
task setup
task 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 task 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 task 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:
task desktop-dev
task 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
task 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):
task desktop-build # populate apps/desktop/dist
npm --prefix apps/desktop run tauri -- build --debug
# Or a full AppImage with embedded assets:
task 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
task 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, runtask 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 --debugortask 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:
task 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
task 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:
task 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 verification & super-fast diff
Specification for cross-engine data verification, migration planning, and fast data-diff work: prove two tables, possibly on different engines or versions, hold the same data, and when they do not, show where fast and legibly.
Status: partial implementation + target architecture.
Built today:
- Desktop Migration Studio generates a plan, source extraction SQL, target load SQL, diff SQL, and a runbook. The default path is Hive -> Snowflake, with PostgreSQL, Oracle, MySQL/MariaDB, Redshift, Databricks/Spark SQL, Trino/Presto, DuckDB/DuckDB-Wasm, Apache Iceberg REST, and AWS S3 Tables in the planner.
- The generated validation flow uses row-hash manifests, row count, key count,
min/max hash fingerprints, manifest tables, and row-level diff SQL. Hive
extraction supports Parquet/CSV in the desktop planner; the shared
irodori-sqlmigration helpers also cover TSV-oriented snippets. - DuckDB/Iceberg flows generate
INSTALL/LOAD iceberg,CREATE SECRET, andATTACH ... TYPE ICEBERGshapes, with warnings for browser credentials, URL sharing, endpoint reachability, and CORS. - Result-grid editing exposes Save Changes and a Row SQL action. Row SQL
turns the selected row from a direct single-table result with a visible primary
or unique key into a reviewable
BEGIN/COMMITwrappedUPDATEinserted into the SQL editor. - The SQL editor has CodeMirror search/replace keybindings (
Ctrl/Cmd+Fand the search panel) and Vim clipboard conflict handling.
Not built yet:
- A live cross-connection executor that runs source and target checks, reconciles
row manifests, and streams a
DiffReport. - The billion-row/100B-row tiered orchestrator, recursive bucket localization,
bucket heatmap UI, and headless
/v1/diffendpoint. - Automatic reconciliation SQL export beyond the selected-row
UPDATEhelper.
The goal remains to land the stable execution/reconciliation boundary before it grows into its own crate or repo. The current desktop implementation is the workflow prototype; the later crate should keep the same plan/runbook/diff language but own the heavy execution model.
Why this is its own thing
This is not “schema diff” (that already exists in irodori-sql/src/schema.rs
diff_schemas()), and it is more than “generate migration SQL” (desktop
Migration Studio and irodori-sql/src/migration.rs cover that). Those pieces
stop at generating SQL. The missing capability is a runtime that executes
the comparison, reconciles manifests, and presents the result interactively.
Driving use cases (from the field): migrating PG↔Oracle↔Snowflake↔Hive↔MySQL,
verifying a version upgrade didn’t drift data, and the daily “did my DELETE
land exactly the rows I meant” check. Hive/Snowflake extraction + compare is
named as the genuinely painful part, so the design optimizes for heterogeneous
sources and large tables first.
What already exists (reuse, don’t reinvent)
| Capability | Where | Reuse as |
|---|---|---|
Cross-engine row-hash SQL (Oracle STANDARD_HASH, MySQL/Snowflake SHA2, Trino MD5(TO_UTF8), PG/Hive/DuckDB MD5) | irodori-sql/src/migration.rs and desktop features/migration/migration-studio.ts | the fingerprint primitive |
| Cross-engine value normalization (CAST -> text, NULL token, whitespace/case) | migration helper normalization functions | the canonicalization primitive; extend for the gaps below |
| Keyed FULL OUTER JOIN diff SQL (+ MySQL/MariaDB anti-join emulation) | migration helper diff SQL | the same-engine fast path |
| Dialect quoting/placeholders | irodori-sql/src/dialect.rs trait SqlDialect | identifier/literal rendering |
| Info-schema metamodel (keys, columns) | irodori-sql/src/metamodel.rs | auto-pick key/compare columns |
| Bounded streaming + cancellation | src-tauri/src/db/stream.rs StreamCtx | pull manifests without OOM |
| Disk spill to temp SQLite + windowed paging | src-tauri/src/db/spill.rs ResultStore | hold million-row manifests off-heap |
| Headless read-only API + audit + guard | ../irodori-kit/irodori-server/src/server.rs ApiServer::dispatch | expose /v1/diff |
| Cell value type | src-tauri/src/db/query.rs Cells = Vec<serde_json::Value> | the comparison unit |
| Selected-row SQL helper | apps/desktop/src/features/results/row-change-sql.ts | reviewable per-row repair/update SQL |
The first two rows are the crux: the hard cross-engine SQL already works and
is tested in migration.rs. We lift those into reusable primitives instead of
re-deriving per-engine hashing.
Strategy: three tiers, cheapest first
Comparing whole tables row-by-row over the wire is the naive (slow) approach. The design is a hierarchy that exits as early as possible — most “are these equal?” questions resolve without moving the data.
Tier 0 COUNT + table fingerprint → O(1) network, answers "equal?" for the common case
Tier 1 chunked fingerprints → O(chunks), localizes mismatch to key-ranges
Tier 2 keyed row reconciliation → O(mismatching rows), exact row/cell diff
Tier 0 — table fingerprint (fast equality)
Push down, per source, one query:
select count(*) as row_count,
<agg-of-row-hash> as table_fingerprint
from <table> where <partition_predicate>;
table_fingerprint is an order-independent aggregate of per-row hashes
(e.g. SUM/BIT_XOR over the numeric form of row_hash_expression, or
MD5(STRING_AGG(row_hash ORDER BY key)) where cheap). Order-independence matters
because heterogeneous engines won’t return rows in the same order. If both
row_count and table_fingerprint match → tables are equal, zero rows moved.
This is the 90% path for “did the upgrade drift?” checks.
Tier 1 — chunked fingerprints (localize)
When Tier 0 differs, split the key space into N deterministic buckets and fingerprint each bucket independently (one grouped query per side):
select <bucket_expr> as bucket,
count(*) as n,
<agg-row-hash> as fp
from <table> where <partition_predicate>
group by <bucket_expr>;
<bucket_expr> is a stable hash-mod of the key (e.g. abs(hashtext(key)) % :N,
engine-mapped). Compare the two small bucket tables locally; only buckets whose
(n, fp) differ proceed to Tier 2. This is a Merkle-style localization: a
handful of differing rows in a billion-row table surfaces a handful of differing
buckets, and we only pull those. Recursable (sub-bucket) for very large tables.
Tier 2 — keyed reconciliation (exact diff)
For each differing bucket, pull only that key-range’s (key, row_hash)
manifest from each side, sorted by key, and do a streaming sorted-merge:
- key in source only →
SOURCE_ONLY(deleted/missing) - key in target only →
TARGET_ONLY(inserted/extra) - key in both, hash differs →
CHANGED→ pull full rows for those keys and produce cell-level diffs (which columns, old vs new value)
Manifests stream through StreamCtx and overflow to ResultStore spill, so the
merge is bounded memory even for large differing sets. Same-engine pairs can
short-circuit Tier 2 into the existing keyed_diff_sql() FULL OUTER JOIN
(single round trip) instead of pulling manifests.
Sampling mode
For “good enough” confidence on huge tables: run Tier 0 plus Tier 1 on a random
sample of buckets (bucket in (:subset)), report a confidence/coverage
figure. Useful for spot-checks during a long migration.
Cross-engine correctness (the hard part)
normalized_column_value() already handles CAST-to-text, NULL token, and
whitespace/case. The diff layer must extend canonicalization for the gaps
migration.rs currently only warns about (≈791–835), because they cause false
diffs across engines:
- Numbers: normalize scale/precision (Oracle
NUMBER↔ SnowflakeNUMERIC↔ PGnumeric) to a canonical decimal string; strip trailing zeros. - Timestamps / timezones: canonicalize to UTC ISO-8601 with fixed precision; decide TZ-naive policy explicitly.
- Floats: round to a configured epsilon before hashing (binary float equality is a trap across engines).
- Booleans / bit: canonical
0/1. - Oracle empty string = NULL: fold to the same NULL token as real NULLs.
- Strings: collation/charset + Unicode normalization (NFC); optional case.
- Bytes/UUID: canonical lowercase hex, no dashes.
Each rule is opt-in per column via a ColumnCanon policy so the user controls
intent (a genuine type change should diff). All of this stays push-down
(rendered into the hash SQL) so it runs in the database, not the client.
Library design — irodori-migration
The execution-free planning and diff primitives live in the sibling
irodori-migration crate. It stays pure logic + SQL generation with no DB
driver (engine-agnostic, like irodori-sql). The desktop app and headless
server supply executors, connection pools, cancellation, and spill storage.
// What to compare.
pub struct DiffSpec {
pub source: TableRef, // engine + qualified name
pub target: TableRef,
pub key_columns: Vec<String>, // auto-filled from metamodel PK if empty
pub compare_columns: Vec<String>,// default: all non-key columns
pub partition_predicate: Option<String>,
pub canon: ColumnCanonMap, // per-column normalization policy
pub bucket_count: u32,
pub mode: DiffMode, // Full | Sampled { buckets } | CountOnly
}
// The crate emits SQL; the host runs it (Tauri/db or server/Registry).
pub trait SqlExecutor {
async fn run(&self, engine: DbEngine, sql: &str) -> Result<RowSet>; // RowSet = (cols, rows, truncated)
}
// Tiered API — each returns the plan to run next, or a verdict.
pub fn fingerprint_sql(spec: &DiffSpec, side: Side) -> String; // Tier 0
pub fn bucket_fingerprint_sql(spec: &DiffSpec, side: Side) -> String; // Tier 1
pub fn manifest_sql(spec: &DiffSpec, side: Side, buckets: &[u32]) -> String; // Tier 2
pub fn reconcile(source: RowStream, target: RowStream) -> DiffStream; // sorted-merge
// Orchestrator that walks Tier 0→1→2 using an executor, short-circuiting early.
pub async fn diff_tables(exec: &dyn SqlExecutor, spec: &DiffSpec) -> Result<DiffReport>;
pub struct DiffReport {
pub equal: bool,
pub source_count: u64,
pub target_count: u64,
pub fingerprint_match: bool,
pub changed: Vec<RowMismatch>, // bounded / streamed for big diffs
pub coverage: Coverage, // full vs sampled
}
pub struct RowMismatch {
pub key: Vec<serde_json::Value>,
pub kind: MismatchKind, // SourceOnly | TargetOnly | Changed
pub cells: Vec<CellDiff>, // for Changed: column, source, target
}
Hashing stays push-down by default (no vendored crypto). If/when we want
in-process hashing for engines lacking good hash functions, add blake3 (fast,
non-crypto-strength is fine here) behind a feature — but push-down is the
default because it avoids moving raw data.
Integration seams
- Migration Studio gains a “Verify” step after “Diff”: it runs
diff_tablesagainst the live source/target connections and renders the report (today the panel only shows generated SQL). The TS side gets typed bindings via the existing typegen path; the diff crate’s request/response types are the contract. - Tauri command
data_diff(spec) -> DiffReportinsrc-tauri/src/db/, backed by anSqlExecutorthat uses the existing connection pool +StreamCtxResultStorefor manifests.
- Headless API:
POST /v1/diffonirodori-server(ApiServer::dispatch), reusing theRegistryto reach both sources, the read-onlyguard, and the audit log. ReturnsDiffReportJSON. Enables CI/automation (“fail the migration job ifequal == false”).
UI — make the diff legible
The problem is that large data diffs are hard to understand. Presentation tiers mirror the algorithm:
- Summary: equal/not, counts per side, % rows changed, fingerprint match, coverage (full vs sampled), elapsed.
- Bucket heatmap: key-space buckets colored by mismatch density — drill into a hot bucket.
- Row list:
SOURCE_ONLY/TARGET_ONLY/CHANGED, keyed, virtualized (reuse the result-grid virtualization). - Cell diff: for a
CHANGEDrow, side-by-side with only the differing cells highlighted (red/green), values rendered with the same formatter as the grid. - Export: the diff as SQL (reconciliation
UPDATE/INSERT/DELETEto make target match source) or as a report.
Performance notes
- Tiers 0/1 are O(1)/O(buckets) network — the whole point is to not pull rows to answer equality.
- Bucket queries across both sides run in parallel (independent connections).
- Tier 2 pulls only differing key-ranges; manifests are
(key, hash)only (narrow), full rows fetched solely forCHANGEDkeys. - Everything is cancellable (reuse the query cancel token) and memory-bounded (spill), so a diff on a billion-row table can’t OOM or hang the app.
Phased plan
- Primitives: keep row hash, keyed diff, bucket fingerprint, and checksum
SQL in
irodori-migration; add the canonicalization extensions (numeric/timestamp/float/oracle-empty). Unit-test SQL rendering per engine. - Report API: extend
irodori-migrationwithDiffSpec/DiffReport,fingerprint_sql/bucket_fingerprint_sql(Tier 0/1), and a host-suppliedSqlExecutortrait. Tests can use a SQLite executor on synthetic data. - Tier 2 reconcile: streaming sorted-merge + cell diff; same-engine
fast-path via
keyed_diff_sql. - Tauri command + Verify panel (single live source↔target).
- Headless
/v1/diff+ a CLI verb for CI. - Sampling mode + bucket heatmap UI; cross-engine canonicalization hardening driven by real PG/Oracle/Snowflake/Hive cases.
Repo boundary
Data-diff primitives stay in the existing irodori-migration sibling repo until
there is evidence that a narrower crate or repository boundary would pay for
itself. The desktop app consumes that crate by tag and keeps live connection,
job, and UI orchestration in irodori-table.
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:
task desktop-typegen
task desktop-typegen-check
task 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
task 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
task 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:
task 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.
Parallel Agent Architecture
Irodori should be developed by several coding agents at once without forcing everyone through the same files. The architecture is extension-first: core owns contracts, connector agents own one connector repository each, and a coordinator serializes registry and generated-catalog changes.
The machine-readable workstream definition lives in
registry/agent-workstreams.json.
Validate it from an irodori-table checkout with:
node tools/docs/agent-workstreams.mjs
Shape
flowchart TB
coordinator["Coordinator agent<br/>registry + generated catalogs"]
host["Extension host agent<br/>ABI + SDK + schema"]
runtime["DB runtime agent<br/>sessions, streaming, cancellation"]
migration["Migration/diff agent<br/>hashing, compare, repair SQL"]
ui["Workbench UI agent<br/>editor, grid, panels"]
docs["Docs agent<br/>generated docs and source docs"]
connectorA["Connector agent A<br/>../irodori-extensions/irodori-extension-hive"]
connectorB["Connector agent B<br/>../irodori-extensions/irodori-extension-snowflake"]
connectorC["Connector agent C<br/>../irodori-extensions/irodori-extension-oracle"]
registry["connector registry<br/>knowledge + marketplace JSON"]
contracts["shared contracts<br/>extension ABI, connection profile, command API"]
coordinator --> registry
host --> contracts
runtime --> contracts
migration --> contracts
ui --> contracts
docs --> registry
connectorA --> contracts
connectorB --> contracts
connectorC --> contracts
connectorA -. read .-> registry
connectorB -. read .-> registry
connectorC -. read .-> registry
Workstream Rules
| Workstream | Parallelism | Owns | Must Not Edit Directly |
|---|---|---|---|
connector-extension | Repeatable; one agent per connector repo | ../irodori-extensions/{repository}/** | Registry JSON, knowledge/engines.json, core Rust DB registry |
extension-host | Single | Extension schema, ABI crate, TS SDK, extension host UI | Connector-specific implementation repos |
db-runtime | Single | Rust DB runtime, transport, profile, streaming, cancellation | Frontend workflow files unless DTOs are agreed |
migration-diff | Single | Migration studio, row hash/diff contracts, high-scale compare design | Connector registry except through coordinator |
workbench-ui | Single | Workbench, query editor, result grid, styles | Rust command DTOs and generated API |
docs-registry | Single | Source docs, generated docs tools, support matrix | App/runtime code without an owning code workstream |
Connector Lane
Connector work is the main parallel lane. Each connector is its own repository under the sibling checkout:
node tools/extensions/scaffold-connector-repos.mjs
cd ../irodori-extensions/irodori-extension-hive
task check
A connector agent can implement Hive, Snowflake, Oracle, Iceberg, vector DBs, or lakehouse storage behavior without touching the desktop registry. It consumes:
irodori.extension.jsonandconnector.config.jsongenerated from the marketplace registry.native/source/snapshots of desktop contracts.../irodori-kit/irodori-connection,../irodori-kit/irodori-extension,../irodori-kit/irodori-connector-abi, and the generated SDK as read-only contracts.
If a connector needs a new manifest field, auth mode, connection profile field,
transport mode, or native ABI call, that is not connector-local work. Open a
contract change in extension-host, db-runtime, or coordinator first.
Serialized Contracts
These files are intentionally serialized because they affect every agent:
knowledge/engines.jsonregistry/catalog/index.jsonregistry/catalog/catalog.jsonregistry/catalog/connector-repositories.jsonapps/desktop/src-tauri/src/db/engine.rsapps/desktop/src-tauri/src/db/profile.rs../irodori-kit/irodori-extension/**../irodori-kit/irodori-connector-abi/**../irodori-kit/packages/extension-sdk/**../irodori-kit/packages/extension-sdk/extension.schema.jsonapps/desktop/src/generated/**
Only the owning workstream should write them. Other agents should treat them as inputs and ask for a contract update when needed.
Local Worktree Layout
Use separate worktrees for app work and separate connector directories for connector work:
git worktree add ../irodori-table-ui -b agent/workbench-ui
git worktree add ../irodori-table-runtime -b agent/db-runtime
git worktree add ../irodori-table-migration -b agent/migration-diff
node tools/extensions/scaffold-connector-repos.mjs
cd ../irodori-extensions/irodori-extension-snowflake
This keeps apps/desktop/src/app/AppWorkbench.tsx, generated files, and registry
JSON out of normal connector branches.
Merge Order
- Coordinator lands registry/marketplace/engine metadata updates.
- Extension-host lands ABI or manifest schema changes.
- DB-runtime lands command/profile/transport changes and regenerates bindings.
- Connector agents update their repositories against the stable contracts.
- UI/migration agents consume generated APIs and connector capabilities.
The order only matters when contracts change. Pure connector implementation
inside one ../irodori-extensions/irodori-extension-* repo can merge
independently.
Required Checks
Run the narrow check for the owning workstream, then the shared registry checks when touching contracts:
node tools/docs/agent-workstreams.mjs
node tools/docs/build-extension-catalog.mjs --check
node tools/docs/support-status.mjs
task extension-manifests
npm --prefix apps/desktop run build
cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml db::engine
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
registry/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 tomonthly.enabled: defaults totrue; set tofalseto keep a source registered but skip network refresh.fetchHeaders: extra HTTP request headers for this source, merged over the refresh defaults (accept,accept-language: en, and the bot user-agent). Use it for upstreams that need a specific header to serve stable content.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: the
knowledge-refresh.ymlGitHub Actions job runs on the 1st of each month, fetches all enabled sources, regenerates the cheatsheets and the app knowledge pack, and opens one consolidated PR whose body is the run digest. The digest is committed asregistry/knowledge-refresh-report.mdand mirrored automatically to knowledge-refresh-report.md by this repo’sknowledge-report-sync.ymlworkflow (daily check and manual dispatch) — no manual docs step remains in the monthly cycle. - Static delivery: the app never fetches upstream docs.
tools/knowledge/pack.mjsderivesregistry/knowledge-pack.jsonand the app-bundled copy from the committedknowledge/pack-facts.json; the in-app Knowledge panel reads the bundled pack and can refresh on demand from the published registry copy. - 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/irodori-table/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://irodori-table.github.io/irodori-docs/data-source-coverage-strategy.html;
this file reconciles intent against the code.
For contract/provisioning and managed-service verification procedures, see External DB contract and verification.
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 (task 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 |
| 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) | Built-in |
| Snowflake | snowflake | HTTP | db/snowflake.rs | 443 | Wired (password/JWT subset) | Built-in |
| 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) | Built-in |
| 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. DuckDB and MotherDuck ship through marketplace connector extensions instead of embedded libduckdb in the core desktop build. Local custom builds may still omit optional legacy connectors for speed. When a custom build omits an optional connector, the app reports that the selected data source is unavailable in this desktop build and links back to this table instead of exposing developer build steps.
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. Marketplace / extension-required engines
These appear in DbEngine, but the core desktop build has no embedded driver for
them. The app asks the user to install the matching connector from
registry/catalog/index.json before a connection can be opened.
| Engine | DbEngine id | Family | Closest existing wire | Note |
|---|---|---|---|---|
| DuckDB | duckdb | Analytical | DuckDb | Installable connector; owns local file and in-memory workflows without compiling libduckdb into the app. |
| MotherDuck | motherduck | Analytical / lakehouse | DuckDb | Installable connector; owns DuckDB/MotherDuck service workflows. |
| 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. Known limitation (#117): reduces every table to a bare read_parquet glob under the table root, ignoring the metastore — partitions stored elsewhere, and ORC/Avro/text tables, read as empty or fail to resolve. The app warns on connect. |
| 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. Their shared
vectorsource-type contract is projected into the catalog for collection/index browsing, vector metadata, similarity search, filtered/hybrid search, and vector-neighbor result views. - 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, Athena, MotherDuck, DuckDB, and Databricks all have
marketplace connectors or recognized entries. Their shared
lakehousesource-type contract is projected into the catalog for catalog/namespace/table browsing, table-format metadata, execution-backend selection, catalog credentials, and starter query templates.
When section 1-4 membership changes, regenerate this page from the registry inputs rather than hand-editing the mirrored snapshot.
Knowledge Refresh Report
Mirrored from the irodori-table generated report
registry/knowledge-refresh-report.md,
produced by the monthly scheduled knowledge refresh (knowledge-refresh.yml,
1st of each month). The source of truth is the table repo; this mirror is
refreshed automatically by knowledge-report-sync.yml (daily check and
manual dispatch).
Run started 2026-08-01T07:08:52.072Z, finished 2026-08-01T07:08:59.361Z (UTC).
| Metric | Count |
|---|---|
| Sources checked | 92 |
| Changed (new snapshot) | 89 |
| Unchanged | 0 |
| Failed | 3 |
| New facts | 453 |
Changed sources (89)
| Source | Product | Latest title |
|---|---|---|
| amazon-s3-docs | Amazon S3 | What is Amazon S3? |
| athena-docs | Amazon Athena | What is Amazon Athena? |
| azure-blob-docs | Azure Blob Storage | Introduction to Azure Blob Storage |
| bigquery-google-sql | BigQuery | Query syntax Stay organized with collections Save and categorize content based on your preferences. |
| bigquery-release-notes | BigQuery | BigQuery release notes Stay organized with collections Save and categorize content based on your preferences. |
| bigtable-docs | Bigtable | Bigtable documentation |
| bigtable-release-notes | Bigtable | Bigtable release notes Stay organized with collections Save and categorize content based on your preferences. |
| cassandra-docs | Apache Cassandra | Welcome to Apache Cassandra’s documentation! |
| cassandra-release-notes | Apache Cassandra | Downloading Cassandra |
| clickhouse-changelog | ClickHouse | Changelog 2026 |
| clickhouse-docs | ClickHouse | Home - ClickHouse Documentation |
| cloud-spanner-docs | Cloud Spanner | Spanner documentation |
| cloud-spanner-release-notes | Cloud Spanner | Spanner release notes Stay organized with collections Save and categorize content based on your preferences. |
| cockroachdb-release-notes | CockroachDB | CockroachDB Releases Overview |
| couchbase-docs | Couchbase | For AI agents: |
| databricks-sql-docs | Databricks | Data warehousing on Databricks |
| datagrip-features | DataGrip | Features |
| dbeaver-sql-editor | DBeaver | SQL Editor |
| dbeaver-supported-databases | DBeaver | Supported Databases |
| dbgate | DbGate | THE SMARTEST SQL & NOSQL database manager |
| dbvisualizer-features | DbVisualizer | Features |
| delta-lake-docs | Delta Lake | Welcome to the Delta Lake documentation |
| duckdb-docs-stable | DuckDB | Redirecting… |
| duckdb-release-notes | DuckDB | Search code, repositories, users, issues, pull requests… |
| dynamodb-docs | DynamoDB | What is Amazon DynamoDB? |
| dynamodb-release-notes | DynamoDB | Document history for DynamoDB |
| elasticsearch-docs | Elasticsearch | Elasticsearch documentation |
| elasticsearch-release-notes | Elasticsearch | Elasticsearch release notes |
| gcs-docs | Google Cloud Storage | Cloud Storage documentation |
| github-copilot-mcp | GitHub Copilot | About Model Context Protocol (MCP) |
| h2-docs | H2 | H2 Database Engine |
| hive-docs | Apache Hive | Documentation |
| hudi-docs | Apache Hudi | Overview |
| iceberg-docs | Apache Iceberg | Documentation 🔗 |
| influxdb3-client-libraries | InfluxDB | InfluxDB 3 API client libraries |
| influxdb3-sql | InfluxDB | Query data with SQL |
| iotdb-docs | Apache IoTDB | Index of /UserGuide/latest |
| irodori-extension-marketplace-catalog | Irodori Extensions | Irodori extension marketplace catalog |
| irodori-extension-repository-index | Irodori Extensions | Irodori connector repository index |
| mariadb-docs | MariaDB | MariaDB Server Documentation |
| mariadb-release-notes | MariaDB | MariaDB Release Notes |
| memgraph-docs | Memgraph | Memgraph Documentation |
| milvus-docs | Milvus | Welcome to Milvus Docs! |
| modelcontextprotocol-spec-2025-06-18 | Model Context Protocol | Specification |
| mongodb-compass | MongoDB Compass | MongoDB Compass: The free GUI tool for data exploration. |
| mongodb-manual | MongoDB | What is MongoDB? |
| mongodb-release-notes | MongoDB | Release Notes |
| motherduck-docs | MotherDuck | MotherDuck documentation |
| mysql-reference | MySQL | MySQL 9.7 Reference Manual |
| mysql-release-notes | MySQL | MySQL :: MySQL 9.7 Release Notes |
| neo4j-browser-docs | Neo4j | Neo4j Browser |
| neo4j-cypher-manual | Neo4j | Introduction |
| neo4j-graph-data-science | Neo4j Graph Data Science | The Neo4j Graph Data Science Library Manual v2026.06 |
| neon-docs | Neon | Neon documentation |
| openai-mcp-connectors | OpenAI API | MCP and Connectors |
| opensearch-docs | OpenSearch | OpenSearch Links |
| opensearch-release-notes | OpenSearch | Version history |
| oracle-26ai-docs | Oracle | Oracle AI Database 26ai |
| oracle-26ai-whats-new | Oracle | Oracle AI Database Oracle AI Database New Features, Release 26ai |
| pinecone-docs | Pinecone | Pinecone documentation |
| postgres-docs-current | PostgreSQL | PostgreSQL 18.4 Documentation |
| postgres-release-notes-current | PostgreSQL | PostgreSQL: Documentation: 18: Appendix E. Release Notes |
| presto-docs | Presto | Presto Documentation ¶ |
| qdrant-docs | Qdrant | Qdrant Documentation |
| questdb-docs | QuestDB | Introduction |
| redis-commands | Redis | Commands |
| redis-release-notes | Redis | Redis Open Source and modules release notes |
| redisinsight | RedisInsight | Redis Insight |
| redshift-docs | Redshift | Introduction to Amazon Redshift |
| redshift-release-notes | Redshift | Cluster versions for Amazon Redshift |
| s3-tables-docs | AWS S3 Tables | Working with Amazon S3 Tables and table buckets |
| schemars | Schemars | Search code, repositories, users, issues, pull requests… |
| scylladb-docs | ScyllaDB | ScyllaDB Open Source Documentation ¶ |
| snowflake-docs | Snowflake | Snowflake Documentation |
| snowflake-release-notes | Snowflake | Snowflake server release notes and feature updates ¶ |
| specta | Specta | Search code, repositories, users, issues, pull requests… |
| sqlite-changes | SQLite | Release History |
| sqlite-docs | SQLite | SQLite Documentation |
| sqlserver-docs | SQL Server | SQL Server technical documentation |
| tidb-docs | TiDB | TiDB Self-Managed |
| timescaledb-docs | TimescaleDB | Tiger Data Documentation |
| trino-docs | Trino | Trino documentation # |
| trino-release-notes | Trino | Release notes # |
| ts-rs | ts-rs | Search code, repositories, users, issues, pull requests… |
| tsql-reference | SQL Server | Transact-SQL reference (Database Engine) |
| typeshare | Typeshare | Search code, repositories, users, issues, pull requests… |
| yugabytedb-docs | YugabyteDB | YugabyteDB Documentation |
| yugabytedb-release-notes | YugabyteDB | Releases |
| yugabytedb-ysql-api | YugabyteDB | YSQL API reference |
Failed sources (3)
| Source | Product | Error |
|---|---|---|
| arangodb-docs | ArangoDB | HTTP 403 |
| firebird-docs | Firebird | HTTP 403 |
| firebird-release-notes | Firebird | HTTP 403 |
New facts by product (453)
| Product | New facts |
|---|---|
| YugabyteDB | 16 |
| BigQuery | 12 |
| Bigtable | 12 |
| Cloud Spanner | 12 |
| DBeaver | 12 |
| DynamoDB | 12 |
| Elasticsearch | 12 |
| InfluxDB | 12 |
| Neo4j | 12 |
| OpenSearch | 12 |
| Redshift | 12 |
| SQLite | 12 |
| Snowflake | 12 |
| PostgreSQL | 11 |
| MongoDB | 10 |
| MySQL | 10 |
| SQL Server | 10 |
| Redis | 8 |
| Apache Cassandra | 7 |
| MariaDB | 7 |
| Trino | 7 |
| AWS S3 Tables | 6 |
| Amazon S3 | 6 |
| Apache Hive | 6 |
| Apache Iceberg | 6 |
| Azure Blob Storage | 6 |
| ClickHouse | 6 |
| CockroachDB | 6 |
| DataGrip | 6 |
| Databricks | 6 |
| DbGate | 6 |
| DbVisualizer | 6 |
| DuckDB | 6 |
| GitHub Copilot | 6 |
| Google Cloud Storage | 6 |
| Irodori Extensions | 6 |
| Memgraph | 6 |
| Milvus | 6 |
| Model Context Protocol | 6 |
| MongoDB Compass | 6 |
| MotherDuck | 6 |
| Neo4j Graph Data Science | 6 |
| Neon | 6 |
| OpenAI API | 6 |
| Presto | 6 |
| Qdrant | 6 |
| RedisInsight | 6 |
| Schemars | 6 |
| ScyllaDB | 6 |
| Specta | 6 |
| TimescaleDB | 6 |
| Typeshare | 6 |
| ts-rs | 6 |
| Amazon Athena | 5 |
| Couchbase | 5 |
| Oracle | 5 |
| Pinecone | 5 |
| Delta Lake | 4 |
| Apache Hudi | 2 |
| TiDB | 2 |
| Apache IoTDB | 1 |
| H2 | 1 |
| QuestDB | 1 |
Generated by tools/knowledge/refresh-report.mjs from the scheduled knowledge refresh. The knowledge SQLite DB itself is gitignored; this report and the regenerated cheatsheets are the reviewable output. Mirrored to the public docs site (irodori-docs).
External DB contract and verification runbook
Last checked: 2026-08-13 JST.
This runbook covers every DbEngine currently declared by Irodori and explains
how to contract/provision external services when local verification is not
enough. The source of truth for engine support remains
registry/data-source-support-status.md and
apps/desktop/src-tauri/src/db/engine.rs.
Policy
- Prefer local verification first when an engine has an embedded mode or an
../irodori-samples/<engine>/compose.yamlfixture. - For managed-only engines, create resources with IaC where the vendor has a stable provider or API.
- Never keep cloud resources running after verification. Set auto-suspend, TTLs, deletion protection off, and budget alerts where available.
- Store cloud credentials outside git. Use short-lived access tokens for manual checks when possible; use service account JSON only for repeatable adapter tests that explicitly need it.
- A source is “Verified” only after an Irodori connect/query path has been exercised, not merely after a vendor CLI query works.
Local-first matrix
| Engine | DbEngine id | Local verification | Contract needed for adapter verification? | IaC path when external |
|---|---|---|---|---|
| PostgreSQL | postgres | ../irodori-samples/postgres | No | Terraform via any Postgres provider only for managed smoke tests |
| MySQL | mysql | ../irodori-samples/mysql | No | Cloud SQL/RDS/etc. optional |
| MariaDB | mariadb | ../irodori-samples/mariadb | No | Cloud/RDS optional |
| SQLite | sqlite | embedded file | No | Not applicable |
| Oracle | oracle | ../irodori-samples/oracle | No for local target | OCI or other managed Oracle optional |
| SQL Server | sqlserver | ../irodori-samples/sqlserver | No | Azure SQL/RDS optional |
| DuckDB | duckdb | embedded / :memory: | No | Not applicable |
| MongoDB | mongodb | ../irodori-samples/mongodb | No | Atlas optional |
| CockroachDB | cockroachdb | ../irodori-samples/cockroachdb | No | Cockroach Cloud optional |
| YugabyteDB | yugabytedb | ../irodori-samples/yugabytedb | No | YugabyteDB Aeon optional |
| TimescaleDB | timescaledb | ../irodori-samples/timescaledb | No | Timescale Cloud optional |
| TiDB | tidb | ../irodori-samples/tidb | No | TiDB Cloud optional |
| H2 | h2 | add local TCP fixture | No after fixture exists | Not applicable |
| ClickHouse | clickhouse | ../irodori-samples/clickhouse | No | ClickHouse Cloud optional |
| Neo4j | neo4j | ../irodori-samples/neo4j | No | Aura optional |
| Memgraph | memgraph | ../irodori-samples/memgraph | Connector extension required | Defer managed verification until the connector is installed |
| InfluxDB | influxdb | ../irodori-samples/influxdb | No | InfluxDB Cloud optional |
| Redis | redis | ../irodori-samples/redis | No | Redis Cloud optional |
| Cassandra | cassandra | ../irodori-samples/cassandra | No | Astra optional |
| ScyllaDB | scylladb | ../irodori-samples/scylladb | No | Scylla Cloud optional |
| QuestDB | questdb | ../irodori-samples/questdb | No | QuestDB Cloud optional |
| Qdrant | qdrant | ../irodori-samples/qdrant | Connector extension required | Defer managed verification until the connector is installed |
| Milvus | milvus | add local compose fixture | Connector not production yet | Defer until connector is wired |
| Elasticsearch | elasticsearch | ../irodori-samples/elasticsearch | Connector extension required | Elastic Cloud optional |
| OpenSearch | openSearch | ../irodori-samples/openSearch | Connector extension required | Amazon OpenSearch Service optional |
| DynamoDB | dynamodb | ../irodori-samples/dynamodb | Connector extension required | AWS account optional |
| ArangoDB | arangodb | ../irodori-samples/arangodb | Connector extension required | ArangoGraph optional |
| Redshift | redshift | No practical local Redshift | Yes | Terraform AWS provider |
| Neon | neon | Postgres-compatible local proxy is not enough | Yes | Neon API/CLI; Terraform provider must be reviewed before use |
| Snowflake | snowflake | No local Snowflake | Yes | Snowflake Terraform provider |
| BigQuery | bigquery | No official local BigQuery API target | Yes | Google Terraform provider |
| Bigtable | bigtable | Emulator exists, but current adapter targets Cloud REST API | Yes | Google Terraform provider |
| Pinecone | pinecone | No local Pinecone; connector not production yet | Yes, after connector exists | Pinecone Terraform provider |
Not-yet-registered lakehouse and federated SQL targets
These sources are in the coverage strategy but are not DbEngine variants yet.
Do not add cloud contracts just to test the current app; provision them when
implementing the adapter, catalog model, or lakehouse execution path.
| Source | Current app status | Local-first check | External / IaC path |
|---|---|---|---|
| Apache Hive / HiveServer2 | Not registered | Local HiveServer2 + Beeline fixture | Self-managed Hadoop/Hive on VMs or managed Hadoop |
| Hive Metastore | Not registered; important for Iceberg catalogs | Local metastore + object store fixture | AWS Glue or managed metastore services |
| Apache Iceberg | Not registered as an engine; priority lakehouse table format | DuckDB/DataFusion/Trino against local object store/catalog | AWS Glue, S3 Tables, REST catalog, warehouse-native Iceberg |
| Trino / Presto | Not registered | Official Trino container with tpch, then Hive/Iceberg catalogs | Helm/Kubernetes or Starburst; Terraform/Helm for infra |
| Databricks / Spark SQL | Not registered | No equivalent local Databricks SQL endpoint | Databricks Terraform provider |
| Delta Lake / Apache Hudi | Not registered; after Iceberg | Local files through DuckDB/DataFusion/Spark fixtures | Databricks or managed Spark/lakehouse |
Existing local verification
Use the sample harness for engines that already have compose fixtures:
task db-verify DB=postgres
task db-verify DB=mysql
task db-all
task db-up DB=postgres
task db-down DB=postgres
For engines with no ../irodori-samples/<engine>/compose.yaml, add a fixture before
creating a cloud contract unless the service is managed-only or the local
emulator does not exercise the same adapter path.
Cloud-only verification levels
Use these levels consistently in PR notes:
| Level | Meaning | Required evidence |
|---|---|---|
| L0 | Vendor resource exists | IaC output or vendor CLI/API select 1 equivalent |
| L1 | Irodori connects | App profile connects and SELECT 1 or equivalent succeeds |
| L2 | Repeatable test | Env-gated integration test or scripted smoke test in repo |
Do not mark an engine “Verified” in data-source-support-status.md unless it
has at least L2 coverage, or a maintainer explicitly accepts L1 as temporary
evidence.
Redshift
Use Redshift Serverless for smoke tests; it is closest to the current Postgres wire adapter and avoids managing a provisioned cluster. AWS documents the serverless endpoint shape as:
workgroup-name.account-number.aws-region.redshift-serverless.amazonaws.com:5439/dev
Contract/provisioning:
- Create or use an AWS account with billing enabled.
- Choose a region where Redshift Serverless is available.
- Create a dedicated VPC security group. Restrict inbound
5439to the verifier’s current IP or VPN CIDR. - Create a Redshift Serverless namespace and workgroup.
- Create a database user for Irodori verification. Keep the admin password in a secret manager or local password manager, not in Terraform state if avoidable.
- Copy the workgroup endpoint and build an Irodori URL:
export IRODORI_REDSHIFT_URL='postgres://USER:PASSWORD@WORKGROUP.ACCOUNT.REGION.redshift-serverless.amazonaws.com:5439/dev?sslmode=require'
IaC skeleton:
resource "aws_redshiftserverless_namespace" "irodori" {
namespace_name = "irodori-smoke"
db_name = "dev"
admin_username = var.admin_username
admin_user_password = var.admin_password
}
resource "aws_redshiftserverless_workgroup" "irodori" {
workgroup_name = "irodori-smoke"
namespace_name = aws_redshiftserverless_namespace.irodori.namespace_name
base_capacity = 8
publicly_accessible = true
subnet_ids = var.subnet_ids
security_group_ids = [aws_security_group.redshift.id]
}
Verification:
- Confirm with a SQL client first:
select 1 as one; - In Irodori, create a
redshiftconnection using the Postgres-style URL. - Run:
select current_database() as db, current_user as user_name;
select 1 as one;
Cleanup:
terraform destroy
References:
- Amazon Redshift Serverless overview: https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-serverless.html
- Redshift Serverless connection strings and default port: https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-connecting.html
- Terraform AWS provider resources:
aws_redshiftserverless_namespace,aws_redshiftserverless_workgroup
Neon
Neon is Postgres wire compatible, but local Postgres does not verify Neon’s endpoint behavior, TLS, auth, suspend/resume, or branch semantics.
Contract/provisioning:
- Sign up or log in to the Neon Console.
- Create a new project. Neon creates a root branch, primary compute, default Postgres database, and default role for the project.
- Pick Postgres version and region close to the verifier.
- If the project is protected, configure IP Allow for the verifier IP.
- Copy the pooled or direct connection string from the dashboard.
IaC:
- Preferred repeatable path today: Neon API or Neon CLI.
- Terraform can be evaluated separately, but do not make a third-party provider mandatory until it is reviewed and pinned.
API-driven provisioning sketch:
export NEON_API_KEY='...'
curl -sS -X POST 'https://console.neon.tech/api/v2/projects' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $NEON_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"project":{"name":"irodori-smoke","pg_version":17}}'
Verification:
export IRODORI_NEON_URL='postgres://USER:PASSWORD@HOST/neondb?sslmode=require'
- Connect in Irodori as engine
neon. - Run:
select version();
select current_database(), current_user;
Cleanup:
- Delete the Neon project.
- If on a paid plan, verify billing/usage limits after deletion.
References:
- Neon project creation and default resources: https://neon.com/docs/manage/projects
- Neon API prerequisites and authentication: https://neon.com/docs/reference/api
- Neon project creation API: https://api-docs.neon.tech/reference/createproject
Snowflake
Snowflake has no local runtime. Use a trial account for connector verification when possible.
Contract/provisioning:
- Sign up for a Snowflake trial account with a valid email.
- Select cloud platform, region, and edition.
- Create a small warehouse with auto-suspend enabled.
- Create a database/schema dedicated to smoke tests.
- Create a least-privilege user/role for Irodori.
- Record the account identifier. Snowflake’s preferred identifier is
organization-account; the account URL format isaccount_identifier.snowflakecomputing.com.
IaC skeleton:
terraform {
required_providers {
snowflake = {
source = "snowflakedb/snowflake"
version = "~> 2.0"
}
}
}
provider "snowflake" {}
resource "snowflake_warehouse" "irodori" {
name = "IRODORI_SMOKE_WH"
warehouse_size = "XSMALL"
auto_suspend = 60
auto_resume = true
}
resource "snowflake_database" "irodori" {
name = "IRODORI_SMOKE_DB"
}
resource "snowflake_schema" "public" {
database = snowflake_database.irodori.name
name = "PUBLIC"
}
Irodori profile:
- Engine:
snowflake - Host:
ACCOUNT_IDENTIFIER.snowflakecomputing.com - User/password: smoke-test user
- Database:
IRODORI_SMOKE_DB - Options:
warehouse=IRODORI_SMOKE_WH,schema=PUBLIC, optionalrole=...
Verification:
select current_version();
select current_database(), current_schema(), current_warehouse();
Cleanup:
terraform destroy, or drop the warehouse/database/user manually.- For trials, track remaining credits and cancel through Snowflake Support if the account should not remain active.
References:
- Snowflake trial account rules: https://docs.snowflake.com/en/user-guide/admin-trial-account
- Snowflake account identifiers: https://docs.snowflake.com/en/user-guide/admin-account-identifier
- Snowflake Terraform provider: https://docs.snowflake.com/en/user-guide/terraform
BigQuery
BigQuery is cloud-only for Irodori’s current REST API adapter.
Contract/provisioning:
- Create or select a Google Cloud project.
- Verify billing is enabled.
- Enable
bigquery.googleapis.com. - Create a dedicated dataset, for example
irodori_smoke. - Create a service account for repeatable checks or use a short-lived OAuth access token for manual checks.
- Grant minimum useful roles:
roles/bigquery.jobUseron the project.roles/bigquery.dataViewer/roles/bigquery.dataEditoron the dataset depending on whether tests create tables.
IaC skeleton:
resource "google_project_service" "bigquery" {
project = var.project_id
service = "bigquery.googleapis.com"
}
resource "google_service_account" "irodori" {
project = var.project_id
account_id = "irodori-bigquery-smoke"
display_name = "Irodori BigQuery smoke test"
}
resource "google_project_iam_member" "job_user" {
project = var.project_id
role = "roles/bigquery.jobUser"
member = "serviceAccount:${google_service_account.irodori.email}"
}
resource "google_bigquery_dataset" "irodori" {
project = var.project_id
dataset_id = "irodori_smoke"
location = "US"
default_table_expiration_ms = 86400000
}
Irodori profile:
- Engine:
bigquery - Database or Host: GCP project ID
- Password: either a short-lived OAuth access token, or service account JSON.
The adapter parses service account JSON when the password starts with
{.
Manual short-lived token:
gcloud auth application-default login
export IRODORI_BIGQUERY_TOKEN="$(gcloud auth print-access-token)"
Verification:
select 1 as one;
select table_schema, table_name
from `PROJECT_ID`.region-us.INFORMATION_SCHEMA.TABLES
limit 10;
Cleanup:
terraform destroy
References:
- Google Cloud Terraform prerequisite flow: https://docs.cloud.google.com/docs/terraform/resource-management/managing-infrastructure-as-code
- BigQuery dataset Terraform sample: https://docs.cloud.google.com/bigquery/docs/samples/bigquery-create-dataset
- Google service account creation: https://docs.cloud.google.com/iam/docs/service-accounts-create
- Google service account key management: https://docs.cloud.google.com/iam/docs/keys-create-delete
Bigtable
Bigtable has tooling and emulators, but the current Irodori adapter targets the Cloud Bigtable REST API, so cloud verification is still required.
Contract/provisioning:
- Create or select a Google Cloud project.
- Verify billing is enabled.
- Enable Bigtable APIs.
- Create a small Bigtable instance with one development cluster.
- Create a table, column family, and one row.
- Create a service account or use a short-lived OAuth access token.
- Grant minimum useful Bigtable IAM roles for table read/list operations.
IaC skeleton:
resource "google_project_service" "bigtable" {
project = var.project_id
service = "bigtable.googleapis.com"
}
resource "google_bigtable_instance" "irodori" {
name = "irodori-smoke"
deletion_protection = false
cluster {
cluster_id = "irodori-smoke-c1"
zone = var.zone
num_nodes = 1
storage_type = "SSD"
}
}
resource "google_bigtable_table" "irodori" {
name = "irodori-smoke-table"
instance_name = google_bigtable_instance.irodori.name
column_family {
family = "cf1"
}
}
Irodori profile:
- Engine:
bigtable - Host: GCP project ID
- Database: Bigtable instance ID
- Password: short-lived OAuth access token or service account JSON.
Verification:
- Seed one row:
echo "project = PROJECT_ID" > ~/.cbtrc
echo "instance = irodori-smoke" >> ~/.cbtrc
cbt set irodori-smoke-table r1 cf1:c1=test-value
cbt read irodori-smoke-table
- In Irodori, run either:
irodori-smoke-table
or:
select * from irodori-smoke-table limit 10
Cleanup:
terraform destroy
rm -f ~/.cbtrc
References:
- Bigtable quickstart instance/table/read/write flow: https://docs.cloud.google.com/bigtable/docs/create-instance-write-data-cbt-cli
- Bigtable IAM access control: https://docs.cloud.google.com/bigtable/docs/access-control
Pinecone
Pinecone is listed in DbEngine, but the current support status marks it as
“recognized, no connector”. Provision Pinecone only when implementing or
verifying that connector.
Contract/provisioning:
- Sign up for Pinecone.
- Create or select a project.
- Create an API key for index/query access.
- Create a serverless index that matches the connector test dimension and metric.
IaC skeleton:
terraform {
required_providers {
pinecone = {
source = "pinecone-io/pinecone"
version = "~> 2.0.0"
}
}
}
provider "pinecone" {}
resource "pinecone_index" "irodori" {
name = "irodori-smoke"
dimension = 3
metric = "cosine"
vector_type = "dense"
spec = {
serverless = {
cloud = "aws"
region = "us-west-2"
}
}
deletion_protection = "disabled"
}
Verification:
- Do not mark Irodori verification complete until
Wire::Pineconehas a production connector. - After the connector exists, test project listing, index metadata, upsert/query, and cleanup.
Cleanup:
terraform destroy
References:
- Pinecone Terraform provider and resource examples: https://docs.pinecone.io/integrations/terraform
Hive, Trino, Databricks, and Iceberg
These are in scope, but they are not current DbEngine variants. Treat them as
adapter-design inputs until the registry grows new variants.
Apache Hive / HiveServer2
Hive can mean two different things in Irodori planning:
- HiveServer2 as a SQL warehouse endpoint.
- Hive Metastore as a catalog for legacy Hive tables and Iceberg catalogs.
Local-first plan:
- Add an
../irodori-samples/hive/compose.yamlfixture only when implementing the adapter. - Include HiveServer2, a metastore database, and a small table.
- Verify with Beeline first:
beeline -u 'jdbc:hive2://localhost:10000/default'
- After Irodori has a Hive adapter, verify:
show databases;
show tables;
select 1;
External / IaC plan:
- Prefer self-managed infrastructure only for integration testing that cannot be reproduced locally.
- On AWS, use EMR or a small Hadoop/Hive stack behind Terraform-managed VPC, security groups, IAM roles, and auto-termination.
- On GCP, use Dataproc with Terraform-managed cluster lifecycle and auto-delete/idle-delete policies.
- Keep HiveServer2 and metastore ports private; access through VPN, SSH tunnel, or a bastion.
Do not make Hive the first lakehouse implementation path unless the task is specifically legacy Hive compatibility. For Iceberg, a catalog-first path is more useful.
References:
- Apache Hive project: https://hive.apache.org/
- Apache Hive documentation: https://hive.apache.org/docs/latest/
Trino / Presto
Trino is the fastest way to test a federated SQL path locally because the
official container includes a default configuration and tpch sample catalog.
Local-first plan:
docker run --name trino -d -p 8080:8080 trinodb/trino
docker exec -it trino trino
Smoke query:
select count(*) from tpch.sf1.nation;
Adapter expectation:
- Irodori should add a
trinoorprestoDbEnginebefore any contract work. - The connector should speak Trino’s HTTP protocol or use a reviewed client crate; do not force it through generic SQL formatting only.
- Metadata should include catalogs, schemas, tables, views, and connector type.
External / IaC plan:
- For self-managed Trino, prefer Kubernetes + Helm; Terraform manages the cluster/network/secrets and Helm release.
- For managed Starburst or equivalent, use the vendor API/provider only after reviewing licensing and cost controls.
References:
- Trino Docker container: https://trino.io/docs/current/installation/containers.html
- Trino Hive connector: https://trino.io/docs/current/connector/hive.html
- Trino Iceberg connector: https://trino.io/docs/current/connector/iceberg.html
Databricks / Spark SQL
Databricks/Spark SQL is cloud-first. Do not try to treat local Spark as proof of Databricks SQL connector behavior; use local Spark only for parser/query-model experiments.
Contract/provisioning:
- Use an existing Databricks workspace or create one through the cloud account’s standard workspace process.
- Create a SQL warehouse with the smallest acceptable size and auto-stop.
- Create or select a catalog/schema/table for smoke tests.
- Create a service principal or PAT with the minimum permissions required for SQL warehouse access.
IaC skeleton:
terraform {
required_providers {
databricks = {
source = "databricks/databricks"
}
}
}
provider "databricks" {}
resource "databricks_sql_endpoint" "irodori" {
name = "irodori-smoke"
cluster_size = "2X-Small"
max_num_clusters = 1
auto_stop_mins = 10
}
Verification after an adapter exists:
select current_catalog(), current_schema();
select 1 as one;
Cleanup:
terraform destroy
References:
- Databricks Terraform provider: https://docs.databricks.com/aws/en/dev-tools/terraform/
- Databricks SQL warehouses: https://docs.databricks.com/aws/en/compute/sql-warehouse/create
Apache Iceberg and catalogs
Iceberg is not a database server. It is a table format plus catalog contracts. Irodori should model Iceberg as a source family with these pieces:
- Catalog: Hive Metastore, AWS Glue, REST, JDBC, S3 Tables, or warehouse-native.
- Storage: S3, GCS, Azure Blob, local filesystem, or compatible object store.
- Execution: DuckDB/DataFusion locally, Trino/Spark/warehouse remotely.
Local-first plan:
- Use DuckDB or Trino against a local object store fixture.
- Seed one small Iceberg table.
- Verify table discovery, schema, snapshots, and
select * limit 10.
AWS IaC sketch for Glue-backed Iceberg:
resource "aws_s3_bucket" "lake" {
bucket = var.bucket_name
force_destroy = true
}
resource "aws_glue_catalog_database" "irodori" {
name = "irodori_smoke"
}
S3 Tables / managed Iceberg:
- Use when testing AWS-managed Iceberg behavior.
- Keep buckets/tables disposable and force deletion in the test account.
Verification after an adapter exists:
select * from irodori_smoke.customers limit 10;
References:
- Apache Iceberg catalog configuration: https://iceberg.apache.org/docs/latest/configuration/
- Apache Iceberg REST catalog spec: https://iceberg.apache.org/spec/#rest-catalog-api
- AWS S3 Tables: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables.html
Future env-gated integration tests
Cloud engines should eventually get opt-in tests under
apps/desktop/src-tauri/tests/integration_db.rs. Use names like:
IRODORI_REDSHIFT_URL=...
IRODORI_NEON_URL=...
IRODORI_SNOWFLAKE=1
IRODORI_BIGQUERY_PROJECT=...
IRODORI_BIGQUERY_TOKEN=...
IRODORI_BIGTABLE_PROJECT=...
IRODORI_BIGTABLE_INSTANCE=...
Test shape:
- Skip if env vars are absent.
- Connect through
connect_impl. - Run the smallest self-contained query or API-equivalent read.
- Call
list_objects_implwhere metadata support exists. - Avoid writes unless the IaC fixture created a disposable schema/table.
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 | ../irodori-samples/postgres |
| MySQL | mysql / sqlx | 3306 | SQL | mysql_samples | ../irodori-samples/mysql |
| MariaDB | mysql wire / sqlx | 3306 | SQL | mariadb_connect | ../irodori-samples/mariadb |
| TimescaleDB | postgres wire / sqlx | 5432 | SQL | timescaledb_samples | ../irodori-samples/timescaledb |
| CockroachDB | postgres wire / sqlx | 26257 | SQL | cockroachdb_connect | ../irodori-samples/cockroachdb |
| YugabyteDB | postgres wire (YSQL) / sqlx | 5433 | SQL | yugabytedb_connect | ../irodori-samples/yugabytedb |
| TiDB | mysql wire / sqlx | 4000 | SQL | tidb_connect | ../irodori-samples/tidb |
| SQL Server | TDS / tiberius | 1433 | SQL | sqlserver_samples | ../irodori-samples/sqlserver |
| DuckDB | embedded libduckdb | — | SQL | duckdb_in_memory | none (embedded) |
| MongoDB | document / mongodb | 27017 | documents | mongo_samples | ../irodori-samples/mongodb |
| SQLite | file / sqlx | — | SQL | sqlite_connect_and_query_round_trip (unit) | none (file) |
| Oracle | thin TNS / oracle-rs | 1521 | SQL | oracle_samples | ../irodori-samples/oracle |
| Redshift | postgres wire / sqlx | 5439 | SQL | — (AWS-only, no local container) | — |
Run them with task db-verify DB=<engine> or task 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
db-feature-samples.json
in the sibling irodori-samples repository 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 | ../irodori-samples/projects/postgres/queries.sql | task db-verify DB=postgres | JSONB, arrays, GIN, extensions, explain JSON |
| MySQL | ../irodori-samples/projects/mysql/queries.sql | task db-verify DB=mysql | JSON functions, FK metadata, windows, explain JSON |
| MariaDB | ../irodori-samples/projects/mariadb/queries.sql | task db-verify DB=mariadb | JSON_VALID/JSON_VALUE, recursive CTEs, windows |
| SQLite | ../irodori-samples/projects/sqlite/queries.sql | cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml sqlite | Embedded SQL, JSON, FTS5, PRAGMA |
| DuckDB | ../irodori-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 | ../irodori-samples/projects/sqlserver/queries.sql | task db-verify DB=sqlserver | T-SQL JSON, identity, TOP, OFFSET/FETCH |
| Oracle | ../irodori-samples/projects/oracle/queries.sql | task db-verify DB=oracle | Thin TNS, SQL/JSON, analytic functions, DBMS_XPLAN |
| MongoDB | ../irodori-samples/projects/mongodb/queries.js | task db-verify DB=mongodb | Collection query, JSON filter, aggregation reference |
| TimescaleDB | ../irodori-samples/projects/timescaledb/queries.sql | task db-verify DB=timescaledb | Hypertables, time_bucket, time-series metadata |
| CockroachDB | ../irodori-samples/projects/cockroachdb/queries.sql | task db-verify DB=cockroachdb | unique_rowid, UPSERT, range inspection |
| YugabyteDB | ../irodori-samples/projects/yugabytedb/queries.sql | task db-verify DB=yugabytedb | YSQL, split tablets, table properties |
| TiDB | ../irodori-samples/projects/tidb/queries.sql | task db-verify DB=tidb | MySQL wire, tidb_version, shard_row_id_bits, explain analyze |
Additional sample engines
The sibling sample repository now covers 23 engines with deterministic seed data and per-engine query projects, including ClickHouse, Redis, Neo4j, Memgraph, Cassandra, ScyllaDB, QuestDB, InfluxDB, Elasticsearch, OpenSearch, Qdrant, ArangoDB, and DynamoDB. Some of these require an installable connector extension rather than a built-in desktop driver. Cloud-only or hosted-only targets such as Redshift, Neon, Snowflake, BigQuery, Bigtable, Milvus, and Pinecone remain reference-only.
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:
task 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 stable GitHub Release: 0.8.5 (
v0.8.5, published 2026-07-30). - Current lightweight prerelease: 0.8.12 (
v0.8.12, published 2026-08-20).
Already in place
.github/workflows/release.yml supports three channels. A v* tag push runs
the lightweight channel and publishes Linux AppImage, .deb, and .rpm
packages as a prerelease. The manual preview channel can append unsigned
universal macOS and Windows packages. The manual stable channel publishes the
full Linux/macOS/Windows set and becomes GitHub’s Latest release. Updater and
platform signing are enabled independently when their credentials are valid;
missing signing credentials no longer block an otherwise complete stable build.
Channel matrix
| Channel | For | Status | Notes |
|---|---|---|---|
| GitHub Releases (Linux) | Linux users | ✅ exists | tag pushes publish AppImage, .deb, and .rpm in the lightweight prerelease lane |
| Stable Windows/macOS releases | end users | ✅ exists | v0.8.5 includes Windows NSIS/MSI and a universal macOS DMG/app archive; current platform packages are unsigned |
| Tauri in-app updater | end users (auto-update) | ✅ exists | v0.8.5 includes latest.json and signed updater artifacts |
| Terminal package download | Linux users | ✅ exists | use gh release download and run the .AppImage, or install the .deb/.rpm |
cargo install --git | Rust devs (headless server) | ✅ exists | installs irodori-server from irodori-kit v0.7.5, 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 stable AppImage without opening a browser:
tmp="$(mktemp -d)"
gh release download --repo irodori-table/irodori-table --pattern "*.AppImage" --dir "$tmp"
chmod +x "$tmp"/*.AppImage
"$tmp"/*.AppImage
Use an explicit tag to test a lightweight prerelease:
tmp="$(mktemp -d)"
gh release download v0.8.12 --repo irodori-table/irodori-table --pattern "*.AppImage" --dir "$tmp"
chmod +x "$tmp"/*.AppImage
"$tmp"/*.AppImage
The current checked assets are:
v0.8.5:Irodori.Table_0.8.5_amd64.AppImage, plus.deb,.rpm, universal macOS, Windows NSIS/MSI, and updater assets.v0.8.12:Irodori.Table_0.8.12_amd64.AppImage, plus.deband.rpm.
Check the release notes before installing: a stable release may publish all platform packages without platform code signing, and a lightweight prerelease does not include macOS, Windows, or updater artifacts.
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 the foundation
tag used by the current desktop workspace:
cargo install --git https://github.com/irodori-table/irodori-kit --tag v0.7.5 --locked irodori-server
The old irodori-table repo command is no longer correct because
irodori-server moved to irodori-kit.
Recommended order
- Keep lightweight tags moving so Linux AppImage/
.deb/.rpmprereleases continue to publish from main. - Verify every stable promotion across Linux, macOS, Windows, and updater assets before making it GitHub Latest.
- Finish platform signing by configuring a Windows signing backend and macOS signing/notarization; the workflow intentionally falls back to unsigned packages when those credentials are absent.
- Keep desktop terminal installs package-based with
gh release download; keepcargo installscoped to theirodori-kitheadless server. - Package managers (brew/scoop/winget/AUR/Flatpak) once the stable assets and checksums are durable enough for manifests.
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 state:
- stable GitHub Release:
v0.8.5; - latest lightweight prerelease:
v0.8.12; - stable assets: Linux AppImage/
.deb/.rpm, universal macOS, Windows NSIS/MSI, and Tauri updater metadata; - lightweight prerelease assets: Linux AppImage/
.deb/.rpmonly.
Public listing metadata
| Field | Value |
|---|---|
| Product name | Irodori Table |
| Generic name | SQL workbench / database client |
| App identifier | dev.irodori.table |
| Repository | https://github.com/irodori-table/irodori-table |
| Homepage | https://irodori-table.github.io/irodori-docs/ |
| Releases | https://github.com/irodori-table/irodori-table/releases |
| Documentation | https://irodori-table.github.io/irodori-docs/ |
| Support URL | https://irodori-table.github.io/irodori-docs/support.html |
| Privacy URL | https://irodori-table.github.io/irodori-docs/privacy.html |
| Disclaimer URL | https://irodori-table.github.io/irodori-docs/disclaimer.html |
| License | MIT OR 0BSD |
| Source license URL | https://github.com/irodori-table/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 v0.7.5 |
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://irodori-table.github.io/irodori-docs/support.html
- https://irodori-table.github.io/irodori-docs/privacy.html
- https://irodori-table.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;
- platform-signed Windows and signed/notarized macOS artifacts (the current stable packages are unsigned);
- committed package-manager, desktop-entry, and appstream manifest templates if those channels become active.
Channel checklist
GitHub Releases
Status: the lightweight Linux lane and full cross-platform stable lane are live.
The stable v0.8.5 release includes updater metadata, but its macOS and Windows
packages are not platform-signed.
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: live. The v0.8.5 stable release includes latest.json and signed
updater artifacts. Updater signing is separate from Windows platform signing
and macOS signing/notarization.
Needed:
- keep the updater keypair valid and available to the stable workflow;
- configure the remaining Windows and macOS signing/notarization secrets;
- verify updater
latest.json, signatures, and platform packages before making a release stable; - 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/irodori-table/irodori-kit --tag v0.7.5 --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
Private Store Registration Runbook Template
Copy this file to a private local note or private archive before filling it in.
Do not commit the filled runbook to irodori-docs or irodori-table.
Do not commit real account IDs, addresses, certificates, private keys, signing passwords, tax records, banking records, recovery codes, or review messages that contain account-specific details.
Owners
- Release owner:
- Security reviewer:
- Legal/account owner:
- Backup maintainer:
Accounts
| Channel | Account owner | Login location | MFA owner | Notes |
|---|---|---|---|---|
| Apple Developer / App Store Connect | ||||
| Microsoft Partner Center | ||||
| Homebrew tap | ||||
| Scoop bucket | ||||
| winget | ||||
| Chocolatey | ||||
| AUR | ||||
| Flathub | ||||
| Snapcraft | ||||
| crates.io |
Signing and credentials
Record where secrets live, not the secret values.
| Secret | Storage location | Rotation owner | Last rotated | Recovery path |
|---|---|---|---|---|
| macOS Developer ID certificate | ||||
| Apple app-specific password | ||||
| Windows code-signing certificate | ||||
| Tauri updater private key | ||||
| Package registry tokens |
Release submission checklist
- Confirm version and tag.
- Confirm release notes.
- Confirm artifact names.
- Confirm sha256 values.
- Confirm signatures/notarization.
- Confirm public support/privacy/disclaimer URLs.
- Confirm package manager manifest diffs.
- Confirm rollback plan.
- Submit package/store update.
- Save review IDs and private review notes in this private doc.
Review notes
Use one section per submission.
YYYY-MM-DD channel version
- Submission ID:
- Reviewer feedback:
- Required changes:
- Public docs changed:
- Private account changes:
- Final status:
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://irodori-table.github.io/irodori-docs/
- Documentation: https://irodori-table.github.io/irodori-docs/
- Releases: https://github.com/irodori-table/irodori-table/releases
- Issues: https://github.com/irodori-table/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 released app version: 0.8.12 (lightweight prerelease); the latest stable release is 0.8.5.
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: lightweight Linux releases, cross-platform stable releases, and the Tauri updater have all shipped. Platform code signing and macOS notarization remain; the stable workflow currently falls back to unsigned packages when those credentials are absent (see distribution.md).
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
Data-source content audit (connectors, snippets, keywords)
A correctness audit of the per-engine completion keywords, SQL snippets, connector catalog, and cheatsheets against each database’s official documentation. Verified across all 36 catalog engines (2026-06-28). Read-only audit — this document records findings; fixes are tracked at the end.
Audited artifacts:
apps/desktop/src/sql/completion-keywords.json— per-dialect keyword lists.apps/desktop/src/sql/default-snippets.json— engine-grouped snippet source (snippets.tsis the loader/validator; snippets are engine-scoped, not one flat set).registry/catalog/catalog.json— connector metadata.docs/cheatsheets/— per-engine cheatsheets.
Verdict
Not “complete/perfect.” The snippet dialect-grouping engine is genuinely well-designed and correct for most engines, but there are three systemic problems and a list of per-engine errors. Honestly perfect today: roughly DuckDB, MotherDuck, PostgreSQL, SQLite.
Systemic findings
- All 36 connector repos were empty stubs marked
verified:true. Everygithub.com/irodori-table/irodori-extension-*returned “This repository is empty” (0 commits) yetcatalog.jsonlisted eachverified:true,version:"0.1.0",runtime:"native". There is also no extension host wired in the app yet, so nothing loads. →verified:trueis unsubstantiated; setfalseuntil the repos carry real code (population is now in progress under../irodori-extensions/). - Keyword completion is not gated by SQL-applicability. Snippets are
correctly gated (
sqlSnippetEngines/isSqlSnippetEngine), so non-SQL stores get no SQL snippets. Butdialect.tsroutes non-SQL stores toStandardSQLandcompletion.ts keywordList()returnsCOMMON_KEYWORDS(SELECT/JOIN/INSERT/RETURNING/UNION) for any engine — leaking SQL completion to 8 non-SQL stores: MongoDB, Redis, DynamoDB, Cassandra, ScyllaDB, Bigtable, Couchbase, ArangoDB. common[]leaksreturningandlimitto every dialect. Both are invalid for MySQL (no RETURNING), SQL Server (OUTPUT/TOP), Oracle (RETURNING INTO/FETCH FIRST), Firebird, and Spanner (THEN RETURN).
What is correct (verified)
- Snippet engine-groups handle dialects well: PG/SQLite
ON CONFLICT, MySQLON DUPLICATE KEY UPDATE, Oracle/SQL Server/Snowflake/Redshift/BigQueryMERGE, SQLitegroup_concatchecksum fallback (nomd5()), ClickHouse correctly excluded from upsert/merge (no UPSERT/MERGE). - Non-SQL stores are correctly excluded from SQL snippets.
- Neo4j cheatsheet is accurate and current for Neo4j 5 Cypher
(
CREATE CONSTRAINT … REQUIRE … IS UNIQUE,SHOW INDEXES,DETACH DELETE, bolt+s URIs) — no deprecated syntax. - Keyword lists for PostgreSQL, MySQL, SQLite, Oracle, Snowflake, BigQuery, Redshift, ClickHouse are accurate (if thin).
- Catalog categorizations are correct except where noted below.
Per-engine issues (with official sources)
| Engine | Issue | Source |
|---|---|---|
| Athena | "format = 'iceberg'" keyword is wrong → Iceberg tables use 'table_type'='ICEBERG'; format is the file format (PARQUET/ORC/AVRO) | docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html |
| Trino, Athena | Support MERGE INTO but are excluded from mergeEngines → no upsert/merge snippet | trino.io/docs/current/sql/merge.html ; docs.aws.amazon.com/athena/latest/ug/merge-into-statement.html |
| Databricks, Trino/Presto | No completion-keywords.json entry at all | docs.databricks.com ; trino.io/docs |
| Snowflake, Redshift | Receive the sp (SAVEPOINT) snippet but neither supports SAVEPOINT | docs.snowflake.com/en/sql-reference/transactions ; docs.aws.amazon.com/redshift/latest/dg/c_SQL_commands.html |
| BigQuery | Classified noExplicitTransactionDmlEngines but supports BEGIN/COMMIT/ROLLBACK TRANSACTION | cloud.google.com/bigquery/docs/transactions |
| QuestDB | Row-level DELETE snippets were removed; time-series signatures are now covered. Remaining audit point: review generic UPDATE-oriented snippets (upd/touch/softdel/updop) against QuestDB’s current DML limits before calling DML coverage complete. | questdb.com/docs/query/sql/sample-by/ ; questdb.com/docs/query/sql/asof-join/ ; questdb.com/docs/query/sql/latest-on/ |
| Firebird | No keyword entry (only common, incl. invalid limit — Firebird uses FIRST/SKIP/FETCH FIRST); supports MERGE + RETURNING but absent from mergeEngines/returningEngines (no upsert/delret) | firebirdsql.org/file/documentation/…/fblangref40-dml.html |
| MariaDB | Supports INSERT/DELETE … RETURNING (10.5+) but absent from returningEngines → delret never offered | mariadb.com/docs/…/insertreturning |
| Iceberg, Delta Lake, Hudi, S3 Tables | Modeled as first-class engines with their own SQL keyword dialects — these are table formats/catalogs accessed via an engine (Spark/Trino/DuckDB/Athena). Hallucinated keyword tokens: Delta "time travel" (→ VERSION AS OF/TIMESTAMP AS OF); Hudi compaction/incremental query/recordkey (configs, not SQL); Iceberg expire_snapshots/rewrite_data_files (Spark CALL procedures), snapshot_id (metadata column); S3 Tables table bucket/namespace (API concepts) | iceberg.apache.org/docs/latest/spark-procedures/ ; docs.delta.io ; hudi.apache.org/docs/configurations/ |
| Cassandra, ScyllaDB | Via the keyword leak, get JOIN/subquery/RETURNING/UNION — invalid in CQL (no joins/subqueries; INSERT is an implicit upsert) | cassandra.apache.org/doc/latest/cassandra/developing/cql/dml.html |
| Cloud Spanner | returning keyword surfaced but GoogleSQL uses THEN RETURN; supports upsert (INSERT OR UPDATE/ON CONFLICT) but gets no upsert snippet | cloud.google.com/spanner/docs/dml-syntax |
| ArangoDB | Catalog categories ["graph","document"] omit key-value (officially multi-model document+graph+key/value) | docs.arangodb.com |
| MySQL | upsert uses VALUES(col), deprecated since 8.0.20 (use AS new(...) alias) | dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-20.html |
| Oracle | Missing high-value keywords: dual, decode, nvl2, rownum, listagg, pivot | docs.oracle.com/…/sqlrf |
| SQL Server | No OUTPUT-clause delete-returning variant (DELETE … OUTPUT deleted.*) | learn.microsoft.com/…/output-clause-transact-sql |
| Non-SQL stores (Mongo/Redis/DynamoDB/Bigtable/Qdrant/Milvus/Pinecone/InfluxDB/IoTDB/Neo4j/Memgraph/ES/OpenSearch) | Not SQL — MQL/commands/PartiQL/API/Cypher/Flux/DSL/vector. SQL snippets correctly withheld; SQL keywords leak (see systemic #2) | per-vendor docs |
Coverage gaps
- Cheatsheets: only 3 of 36 engines in the public docs (postgres, neo4j,
questdb). The table repo keeps only generator snapshots it needs locally;
QuestDB’s human-facing page now lives in
irodori-docs/src/cheatsheets/. MySQL/MariaDB/SQLite/SQL Server listed “Planned”; Oracle/Firebird/all others absent. - Connectors: 0 of 36 implemented at audit time (empty repos).
Fixes applied (2026-06-28, verified: tsc 0 / 342 tests)
- ✅ Keyword completion gated by SQL-applicability (
completion.tskeywordList): non-SQL stores no longer receive SQLSELECT/JOIN/RETURNINGkeywords — they surface only their own dialect terms (e.g. Elasticsearch_search/aggs). Systemic finding #2 resolved. - ✅
common.returningremoved fromcompletion-keywords.json; moved to the engines that support it (postgres, sqlite, duckdb, mariadb; the cockroachdb/yugabytedb/neon lists already had it). - ✅ Athena + S3 Tables keyword
format = 'iceberg'→table_type = 'iceberg'. - ✅ Delta
time travel→version as of/timestamp as of; Hudicompaction/incremental query/recordkeyremoved (leftmerge into). - ✅ MERGE: added
trinoPresto,athena,firebirdtomergeEngines. - ✅ RETURNING: added
mariadb,firebirdtoreturningEngines. - ✅ SAVEPOINT: new
savepointEnginesgroup excludes Snowflake/Redshift (which have BEGIN/COMMIT but no SAVEPOINT); the genericspsnippet uses it. - ✅ QuestDB DELETE: new
deleteEngines/limitDeleteEngines/noTxnDeleteEnginesgroups exclude QuestDB fromdel/delop(it keeps SELECT/UPDATE/softdel, which are valid). - ✅
common.limitfiltered fororacle/sqlserver/firebirdincompletion.tskeywordList(NON_LIMIT_SQL_ENGINES) — they useTOP/FETCH FIRST/FIRST..SKIP, notLIMIT. (Done in code rather than movinglimitacross ~23 engine lists, both to avoid the churn and to avoid colliding with concurrent edits tocompletion-keywords.json.) - ✅ Firebird/Oracle/SQL Server keyword additions (Firebird entry;
Oracle
dual/decode/rownum/listagg/pivot; SQL Serveroutput) — landed via the connector/keyword work incompletion-keywords.json. - ✅ BigQuery transactions: dedicated
begin/tx/commit/rollbacksnippets useBEGIN TRANSACTION/COMMIT TRANSACTION/ROLLBACK TRANSACTIONwithout adding BigQuery to the genericbegin;transaction group. - ✅ QuestDB signatures: added
SAMPLE BY,LATEST ON, andASOF JOINsnippets for QuestDB time-series extensions. - ✅ QuestDB time-series expansion: added richer
SAMPLE BYfill/range/ alignment andASOF JOIN TOLERANCEsnippets, QuestDB-specific completion keywords, and a hand-seededirodori-docs/src/cheatsheets/questdb.md. - ✅ SQL Server delete-returning: added a
delretvariant usingOUTPUT deleted.*.
Remaining (deferred — larger/owned elsewhere)
catalog.jsonverified:true— the connector repos under../irodori-extensions/are now being populated (no longer empty), so the flag is becoming legitimate. Owned by the connector-population effort; not edited here.- Public cheatsheet coverage (3/36 engines).
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 engine syntax reference (driver/decoding internals) and data-source support status (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 extension notes | Seed (flagship graph/Bolt page) |
| postgres.md | PostgreSQL (+ Cockroach/Yugabyte/Redshift/Timescale/Neon; H2 wire notes) | 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 |
| oracle.md | Oracle | Planned |
| sqlserver.md | SQL Server | Planned |
| duckdb.md | DuckDB / MotherDuck | Planned |
| mongodb.md | MongoDB | Planned |
| redis.md | Redis | Planned |
| cassandra.md | Cassandra / ScyllaDB | Planned |
| clickhouse.md | ClickHouse | Planned |
| snowflake.md | Snowflake | Planned |
| bigquery.md | BigQuery | Planned |
| bigtable.md | Bigtable | Planned |
| influxdb.md | InfluxDB | Planned |
New cheatsheets are added only for engines that are at least Wired in
data-source-support-status.md. An engine
that is “Recognized, extension required”
or “Not registered” gets a row in the support-status doc, not a cheatsheet, until
it can actually connect.
Maintenance queue
Seed the next pages in the same order as the support-status table, prioritizing
engines with verified or wired query paths and enough source coverage in
knowledge/sources.json: duckdb.md, mongodb.md, redis.md,
cassandra.md, clickhouse.md, snowflake.md, bigquery.md, bigtable.md,
and influxdb.md.
Some sibling connector implementations can run ahead of the root registry. Until the registry and support-status page promote an engine to Wired or Extension, keep those details as related notes under the nearest wired cheatsheet instead of publishing a standalone page.
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.
エンジンのチートシート
データベースごとに、Irodoriからの接続方法、クエリモデル、エンジン固有の注意点を素早く確認できるページです。詳しいドライバー/デコード仕様はエンジン構文リファレンス、対応状況はデータソース対応状況を参照してください。
各チートシートは、irodori-table内のローカル知識入力(knowledge/cheatsheets/*.jsonと知識DB)から自動生成されることを意図しています。ページが生成されるまで、手動で種をまき<!-- seed -->とマークすることも可能です。生成管理とドリフトルールはrepository-boundaries.mdに記録されています。
目次
| チートシート | 対応エンジン | 状況 |
|---|---|---|
| neo4j.md | Neo4j(グラフ、Bolt/Cypher);Memgraph拡張メモ | 種まき(グラフ/Boltの主要ページ) |
| postgres.md | PostgreSQL(+ Cockroach/Yugabyte/Redshift/Timescale/Neon;H2ワイヤーメモ) | 生成済み(knowledge/cheatsheets/postgres.json) |
| questdb.md | QuestDB(Postgresワイヤ+時系列SQL拡張) | 種まき |
| mysql.md | MySQL / MariaDB / TiDB | 計画中 |
| sqlite.md | SQLite | 計画中 |
| oracle.md | Oracle | 計画中 |
| sqlserver.md | SQL Server | 計画中 |
| duckdb.md | DuckDB / MotherDuck | 計画中 |
| mongodb.md | MongoDB | 計画中 |
| redis.md | Redis | 計画中 |
| cassandra.md | Cassandra / ScyllaDB | 計画中 |
| clickhouse.md | ClickHouse | 計画中 |
| snowflake.md | Snowflake | 計画中 |
| bigquery.md | BigQuery | 計画中 |
| bigtable.md | Bigtable | 計画中 |
| influxdb.md | InfluxDB | 計画中 |
新しいチートシートは、データソース対応状況で少なくともWiredと認定されたエンジンに追加します。「認識済み、拡張が必要」または「未登録」のエンジンは、実際に接続できるようになるまで対応状況ページだけで管理します。
メンテナンスキュー
次のページは対応状況表の順序に合わせ、検証済みまたは接続済みのクエリパスと十分な公式情報があるエンジンを優先します:duckdb.md、mongodb.md、redis.md、cassandra.md、clickhouse.md、snowflake.md、bigquery.md、bigtable.md、influxdb.md。
ページのフォーマット(各チートシートのテンプレート)
この順序を守ることで、生成ツールが決定論的にページを作成でき、読者も習慣化しやすくなります。
- 概要 — ワイヤ/ドライバー、デフォルトポート、クエリ言語、Irodoriのサポート状況、そして「このエンジンの特徴は何か?」を一行で。
- 接続 — Irodoriの接続フィールドと生のURL/DSN形式、最小限の動作例。
- クエリモデル — 入力する内容、返ってくる内容、行制限の挙動。
- 基本的なステートメント — 80%のケースに対応できる、コンパクトで実行可能なクエリセット。
- オブジェクトの一覧表示 — Irodoriのオブジェクトブラウザのようにオブジェクトをリストアップする方法。
- Irodori固有の挙動 — このアプリ特有のマッピングや癖(デコード、オブジェクトブラウザのマッピング、未実装部分)。
- 注意点 — 実際に人を困らせる小さなポイント。
- ソース — このページが生成された
knowledge/sources.jsonのID。
Sourcesフッターは重要で、各ページを公式ドキュメントに紐付け、ページの鮮度を確認できる仕組みになっています。
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 data-source support status |
| 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. - See the engine syntax reference for deeper driver and decoding details.
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 | Neo4j is Wired (graph); Memgraph uses an installable extension — see data-source support status |
| What’s different | Data is nodes and relationships, not rows. You query patterns with Cypher and get back records of nodes/relationships/scalars. |
| Optional analytics | Graph Data Science (GDS) procedures are available only when installed/enabled on the connected Neo4j database. |
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
SHOW PROCEDURES YIELD name WHERE name STARTS WITH 'gds.' RETURN name LIMIT 25; -- GDS present?
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;
Graph Data Science / ML
Neo4j Graph Data Science is a Neo4j-side library/service, not part of Bolt or the
base connector. Irodori can run the gds.* Cypher procedures when the connected
database exposes them; otherwise these queries fail with an unknown procedure
error and the base graph browser still works.
Read-only checks that are safe for exploration:
-- Check whether GDS procedures are available
SHOW PROCEDURES YIELD name, description
WHERE name STARTS WITH 'gds.'
RETURN name, description
ORDER BY name
LIMIT 50;
-- Projected in-memory graphs
CALL gds.graph.list()
YIELD graphName, nodeCount, relationshipCount, schema
RETURN graphName, nodeCount, relationshipCount, schema
ORDER BY graphName;
-- ML training pipelines and trained models
CALL gds.pipeline.list()
YIELD pipelineName, pipelineType, creationTime, pipelineInfo
RETURN pipelineName, pipelineType, creationTime, pipelineInfo
ORDER BY pipelineName;
CALL gds.model.list()
YIELD modelName, modelType, modelInfo, loaded, stored, published
RETURN modelName, modelType, modelInfo, loaded, stored, published
ORDER BY modelName;
Algorithms run against a projected graph in the GDS graph catalog. Prefer
stream or stats mode for inspection; mutate changes the in-memory graph and
write persists results back into Neo4j.
CALL gds.degree.stream($graphName)
YIELD nodeId, score
RETURN gds.util.asNode(nodeId) AS node, score
ORDER BY score DESC
LIMIT $limit;
ML pipelines are catalog objects too. Node classification and link prediction pipelines need feature properties in the projected graph before training.
Irodori-specific behavior
- Object browser mapping: node labels are shown as graph objects and relationship types as graph objects. Their columns are sampled property keys, so a property that only appears on a few nodes can be missed — treat the column list as representative, not exhaustive.
- Extension metadata additionally reports relationship endpoints,
indexes/constraints, inferred property types from samples, and optional GDS
graph/model/pipeline catalog objects when
gds.*procedures are available. - Results are tabular today. Node/relationship records show as JSON property cells. A query-result graph visualization is a planned shared capability (P1, see data-source coverage strategy → 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 has an installable extension implementation in
irodori-extension-memgraph. Core treats memgraph as extension-required, so
keep Memgraph-specific notes here instead of publishing a standalone
memgraph.md.
Most Cypher examples above apply. Metadata can differ from Neo4j’s CALL db.*
procedures; the extension uses portable pattern queries for labels and
relationship types, for example:
MATCH (n) UNWIND labels(n) AS label RETURN DISTINCT label ORDER BY label;
MATCH ()-[r]->() RETURN DISTINCT type(r) AS relationshipType ORDER BY relationshipType;
Sources
Generated from knowledge/sources.json:
neo4j-cypher-manual— https://neo4j.com/docs/cypher-manual/current/neo4j-browser-docs— https://neo4j.com/docs/browser/neo4j-graph-data-science— https://neo4j.com/docs/graph-data-science/current/memgraph-docs— https://memgraph.com/docs
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.