Busabase
Busabase는 AI 에이전트를 위한 오픈소스(MIT) 데이터베이스 및 작업 공간입니다
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
rimor (Latin): I probe, I search thoroughly.
A terminal workbench for relational databases: browse the catalog, write SQL
in tabs with syntax highlighting, and explore results in a scrollable grid.
It supports PostgreSQL, SQL Server and SQLite.README 전문 보기 ↗rimor (Latin): I probe, I search thoroughly.
A terminal workbench for relational databases: browse the catalog, write SQL in tabs with syntax highlighting, and explore results in a scrollable grid. It supports PostgreSQL, MySQL and MariaDB, SQL Server and SQLite.
╭─ 1 Explorer ─────────╮╭─ 2 ○ untitled-1 ─ ● untitled-2 ● ──────────────────────────────────────╮
│ + New connection ││ 1 SELECT c.name, c.city, count(o.id) AS orders, sum(o.total) AS total │
│ ││ 2 FROM customers c LEFT JOIN orders o ON o.customer_id = c.id │
│ ▾ ◈ shop sqlite ││ 3 GROUP BY c.id ORDER BY total DESC │
│ ▾ ▫ Tables 2 ││ │
│ ▾ ▦ customers ││ │
│ ▾ ▫ Columns 4 ││ │
│ ⚷ id INTEG…│╰─ ◈ shop ────────────────────────────────────────────────────────────────╯
│ · name TEXT│╭─ 3 Results ────────────────────────────────────────────────────────────╮
│ · city TEXT││ name city orders total │
│ · since DA…││─────────────────────────────────────────────────────────────────────────│
│ ▸ ▪ Indexes ││ 1 Grace Hopper Arlington 2 995 │
│ ▸ ▦ orders ││ 2 Ada Lovelace London 2 155.5 │
│ ▸ ▪ Views ││ 3 Barbara Liskov Boston 1 42.25 │
│ ▸ ▪ Indexes ││ 4 Edsger Dijkstra NULL 0 NULL │
│ ▸ ▪ Triggers ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
╰───────────────────────╯╰─ ✓ 4 rows · <1 ms ──────────────────────────── 2/4 · name text y copy ─╯
dbo. . on a database lists the empty ones too.
SQLite tables show their rowid: the implicit one, or the
INTEGER PRIMARY KEY column that stands in for it. / filters what is
loaded by name as you type.s on a table, view, column, foreign key, routine, sequence
or index offers ready-made SQL in that database's dialect: the first rows,
an insert or update to fill in, a call with every parameter. It opens in
a new tab, and runs only when you run it.ctrl+e changes it. Tabs save
to .sql files, and the session (tabs, unsaved text, contexts, layout)
comes back on the next start.esc stops
fetching but keeps what came. They are stored compactly (a few bytes of
overhead per cell), so millions of rows are fine. The grid scrolls
vertically by row and horizontally by column, with right-aligned numbers
and visible NULLs. Statements that
change data show the rows affected. Errors show the database's code and
message, plus the failing line with a caret where the driver reports a
position.e in the results writes the result as CSV, TSV, JSON, JSON
Lines, SQL INSERTs or Markdown, to a file or the clipboard; when only
part of a large result is in memory, it can run the query again into the
file. See Exporting results.rimor is a single binary with no runtime dependencies, for Linux, macOS and Windows on amd64 and arm64.
xattr -d com.apple.quarantine rimor after
unpacking; on Windows, SmartScreen may ask you to confirm.rimor (built from source) or rimor-bin (prebuilt) from
the AUR, e.g. yay -S rimor.go install rimor.dev/cmd/rimor@latest. Right
after a release, @latest can still give the previous version for up to
half an hour, while Go's module proxy refreshes; name the version
(@v0.8.1) to get it at once.go build ./cmd/rimor.rimor -version prints the version.
Every 4 hours, at startup and while it runs, rimor asks GitHub whether a
newer release is out. When one is, the query pane's top border shows it
(↑ v0.7.0, linked to the release notes), and once per release a note
says how to update: the release page, or the go install command for a
binary built that way. rimor -version mentions it too.
The check is one HTTPS request to api.github.com, without credentials.
GitHub sees your address and, in the User-Agent, rimor's version; nothing
else is sent. It runs in the background, gives up after 3 seconds, and
fails silently: offline, behind a firewall, or past GitHub's limit for
anonymous requests (60 an hour per address, shared in an office), rimor
just tries again an hour later. The answer is kept in update.json
beside the session, which other rimor windows share.
Installs from a system package manager (the AUR packages, under /usr)
never check, since the package manager updates them. Development builds
never check either. To turn it off, set check_updates = false in
config.toml.
The Nerd Font icons appear automatically when your terminal bundles them
(kitty, Ghostty, WezTerm) or a Nerd Font is installed; otherwise rimor uses
plain Unicode symbols. See icons in Configuration.
enter on a result cell opens it. The value is selected, so ctrl+c copies
it. When rimor can tell which table row the cell comes from, the value can
be changed in place:
| Key | Single-line value | Multi-line value or JSON |
|---|---|---|
enter | save | new line |
ctrl+s | save | save |
alt+enter | new line | new line |
ctrl+f | format JSON | |
ctrl+n | set NULL | set NULL |
esc | close without saving | close without saving |
Saving runs the UPDATE shown below the value.
JSON columns open highlighted in a larger editor: json and jsonb on
PostgreSQL; on SQL Server the 2025 json type and text columns with an
enabled ISJSON check; on SQLite, which has no JSON type, columns declared
JSON or JSONB and columns with a json_valid check. They are checked
before saving:
invalid JSON is never sent, and the cursor goes to the fault. jsonb and
SQL Server's json open pretty-printed, since the database stores its own
form anyway, and so does SQLite's binary JSONB, which rimor edits as text
and stores back as JSONB. PostgreSQL's json and text columns keep text
exactly as written, so they open as stored and ctrl+f formats them on
request.
Editing needs a result from a single table that includes the table's
primary key, or a unique key on non-null columns; on SQLite, a table
without one can be edited through its rowid (SELECT rowid, …). Key columns and
columns the database computes are not editable. Editing MySQL and MariaDB
results is not available yet: their driver does not say which table and
column each result column comes from, which editing needs to be safe. The update only applies if
the cell still holds the value it was opened with; otherwise rimor says the
row changed and leaves it alone. It runs on the tab's connection, so inside
an open transaction it can still be rolled back.
e in the results opens the export dialog. ↑/↓ move between its
fields, ←/→ change a choice, and enter exports.
| Format | Notes |
|---|---|
| CSV | a header row, RFC 4180 quoting, ; or ,, an optional BOM for Excel |
| TSV | tabs, quoted where a value holds a tab, a quote or a line break |
| JSON | an array of objects: numbers as numbers in numeric columns, true/false, JSON columns as JSON, NULL as null |
| JSON Lines | one object per line, for large results and tools such as jq |
| SQL | INSERTs of 100 rows each, in the tab's dialect, into the result's table when it comes from one, else result |
| Markdown | a table for issues and documents |
; where numbers are written
with a decimal comma (Italian, German, French…; on Windows, the list
separator in the region settings), , elsewhere. The other one is a key
away, and the choice is remembered, with the format, how CSV writes
NULL (empty, NULL or \N) and the folder, in export.json beside the
session.;:
there, numeric columns write 120,5 where the locale writes decimals with
a comma, as its spreadsheets expect, and the dialog says so. A CSV
separated by , always writes 120.5, and so do the other formats. Text
columns are never changed: a version such as 1.2.3 keeps its dots.result_memory_mb, and
the dialog then says not every row is here. Rows: all runs the
statement again on the tab's session, so temp tables still apply, and
streams every row into the file without the limit, binary values whole;
esc stops it. It is offered only for statements that do not write, since
running a write twice could change data twice.The change script of a procedure, function, view or trigger (s on it in
the explorer; for routines it comes first, so S opens it) puts its
definition in a tab, and the status line says what the tab changes.
Running the whole tab applies it; a selection runs as plain SQL.
| Engine | How it is applied |
|---|---|
| PostgreSQL | CREATE OR REPLACE, as the server writes the definition. A view can only gain columns at its end; a function whose parameter types change becomes a second overload |
| SQL Server | ALTER, after the module's own ANSI_NULLS and QUOTED_IDENTIFIER settings and a GO |
| MariaDB | CREATE OR REPLACE |
| MySQL | views with CREATE OR REPLACE. A routine or trigger cannot be changed in place: rimor creates your version under a temporary name first, so an error leaves the old one untouched, then drops the old one and creates yours, in the sql_mode it was created in. Privileges granted on a routine go with it |
| SQLite | the view or trigger is dropped and created again inside a savepoint: an error leaves it as it was |
Before applying, rimor compares the definition on the server with the one the tab opened. If someone changed or dropped the object since, it asks before overwriting; after each change, the tab compares with what it applied. The tab is saved with the session, object included, and forgets the object when its context changes. Nothing is applied on a read-only connection, nor on MySQL inside an open transaction, which the change would commit.
Press a in the explorer, or Enter on New connection, and give it a
name, a driver and a connection string. ctrl+t in the form tests the
connection.
| Driver | Connection string |
|---|---|
| PostgreSQL | postgres://user:pass@localhost:5432/db?sslmode=disable |
| SQL Server | sqlserver://user:pass@localhost:1433?database=db |
| SQLite | /path/to/database.db |
| MySQL, MariaDB | mysql://user:pass@localhost:3306/db, or the driver's own user:pass@tcp(localhost:3306)/db |
Characters with a special meaning in URLs must be percent-encoded in
passwords (@ is %40). For SQL Server, the URL path names an instance,
not a database; the database goes in ?database=. Add
&TrustServerCertificate=true for servers with self-signed certificates.
For MySQL and MariaDB, the options after ? are
go-sql-driver/mysql's
(tls=true, timeout=5s); a MySQL database is what other engines call a
schema, so the explorer lists each database's tables, views, routines and
triggers directly.
Passwords are kept in the system keychain: Keychain on macOS, Credential
Manager on Windows, the Secret Service (GNOME Keyring, KWallet) on Linux.
connections.json, readable only by you, keeps each connection string
without its password, and rimor puts it back when connecting. Passwords
saved by earlier versions move to the keychain on the first start. Where
there is no keychain, such as a server without a desktop session, they stay
in connections.json, and rimor says so.
The keychain keeps passwords out of a file that is easy to copy, back up or
read by mistake. It does not hide them from programs running as you: on
Linux and macOS those can usually read your unlocked keychain too. A
connection string without a password also works, when the driver finds one
elsewhere: ~/.pgpass or PGPASSWORD for PostgreSQL, Windows authentication
for SQL Server.
Mark a connection read-only in the same form. On PostgreSQL and MySQL
the server then refuses writes, DDL included, and on SQLite the engine does. SQL Server has no
read-only session setting, so rimor refuses statements that write, EXEC
included; for a hard guarantee, use a login without write permissions.
To look at a database once, without adding it to your connections, give it on the command line:
rimor ./app.db
rimor postgres://[email protected]/erp
rimor -readonly sqlserver://[email protected]?database=erp
rimor "host=db.local dbname=erp user=me"
rimor mysql://[email protected]/shop
rimor recognises PostgreSQL, SQL Server and MySQL connection strings, in
URL form or the driver's own (key=value, or user@tcp(host)/db), and SQLite
files, which must exist. The connection comes
first in the explorer, marked temporary, with a tab open on it; your saved
connections are there too. Nothing about it is saved: not in
connections.json, not in the keychain, and your session is neither
restored nor saved, so your usual tabs are there the next time you start
rimor without one. To keep the connection, press e on it and save it.
-readonly works like the connection form's read-only option.
Leave the password out: a password on the command line ends up in your
shell history, and other users of the machine can see it in the process
list. When the server asks for one, rimor asks you and keeps it in memory
only. ~/.pgpass, PGPASSWORD and Windows authentication work too.
rimor can work alongside an AI agent. With rimor open in one terminal and,
say, Claude Code in another, ask "from ERP, the customer orders whose
delivery date has passed": the agent looks up the tables it needs, and the
query appears in a new tab in rimor, marked with a sparkle (✶ with plain
icons), waiting for you. It runs only when you run it.
Register rimor with the agent once:
claude mcp add rimor -- rimor mcp
Other MCP clients run rimor mcp as a stdio server. It holds no
connections of its own: it talks to the rimor you have open, through a
socket only your user can open (in $XDG_RUNTIME_DIR, or the temporary
folder). With rimor closed, the agent is told to ask you to start it.
| Tool | What the agent gets |
|---|---|
list_connections | Each connection's name, driver and read-only flag, and the server version once it is open |
list_objects | One level of the explorer: databases, schemas, tables, views, functions… |
search_objects | Tables, views, routines and columns whose names contain some text |
describe | A table's columns, types, defaults, comments, keys, indexes, and foreign keys in both directions |
open_query | Opens a tab with its SQL, on a connection and database, and shows it to you |
update_query | Revises a tab it opened; ctrl+z brings back the previous version |
list_tabs, read_tab | Your tabs, their SQL and selection, and how the last run went |
wait_for_run | Waits until you run a tab, then reports how it went |
read_results | The rows of a tab whose results you shared, a page at a time |
What the agent does not get:
Some work takes many queries, such as finding why a SQL Server instance
slowed down. Instead of copying each query in and each result back out,
press alt+a on the tab (or ctrl+g then a) to let the agent read its
results. The agent can also ask, which shows in the tab's status line.
Then the loop is: the agent revises the tab, you read the query and run it,
and wait_for_run hands the agent the outcome and the first rows. You
still review and run every query.
alt+a again. It is never saved, and
the status line says agent reads results while it lasts.read_results returns pages of 100 rows by default and 500 at most,
about 64 KB at a time, with cells over 1 KB cut.UPDATE, DROP, EXEC and the like), the
reminder under it turns into a warning. For diagnostics, a read-only
connection makes sure nothing can.PRINT and SET STATISTICS output reach it only for a shared
tab, since they can carry data.Rows you share go to the agent's model provider, like everything the agent
reads. It also reads your catalog, comments included. To turn agent access off, set agent = false in
config.toml.
F1 shows the keys that apply where you are: the focused pane or the
open dialog, then the app-wide ones, with your own bindings. tab in it
lists every key, and typing filters them. Outside text input ? opens it
too, and so does ctrl+g then ?.
App-wide shortcuts work in every pane, including the editor. Each one also
works as the leader key (ctrl+g) followed by a second key; press ctrl+g
on its own to list them.
| Keys | Action |
|---|---|
F1 | The keys that apply here; tab in it lists every key |
alt+1 alt+2 alt+3 | Focus explorer, query, results |
alt+f | Toggle full screen for the focused pane |
shift+alt+1/2/3 | Show a pane in full screen |
ctrl+enter F5 alt+enter | Run the selection, or the whole tab |
ctrl+t | New tab, in the context of the explorer's selection |
ctrl+o | Open a .sql file |
alt+shift+←/→ alt+shift+↑/↓ | Resize the explorer / the query editor |
alt+= | Reset pane sizes |
alt+a | Let the agent read this tab's results, or stop it |
ctrl+q | Quit |
Explorer: j/k or the arrows move, enter/l expands, h collapses,
a adds a connection, e edits it, d deletes it, r refreshes, x
disconnects, . shows or hides a database's empty schemas.
s lists the scripts for the object under the cursor, and S opens the
first one straight away:
| Object | Scripts |
|---|---|
| Table | select the first rows, count, insert, update or delete a row by its key, add a column, drop (commented out) |
| View | select the first rows, count, change, drop (commented out) |
| Materialized view | select the first rows, count, drop (commented out) |
| Column | its most common values |
| Foreign key | join the two tables; rows whose referenced row is missing |
| Function, procedure | change; a call with a NULL for each parameter, named and typed |
| Trigger (SQLite, MySQL) | change |
| Sequence | its current value; restart |
| Index | drop (commented out) |
Values to fill in are NULL, so a script run as it is changes nothing:
WHERE id = NULL matches no row, and drops are commented out. Inserts leave
out the columns the database fills in (identity, serial, computed). The
first-rows scripts select script_rows rows, 100 by default.
/ filters the explorer as you type: it keeps the rows whose names contain
the text, ignoring case, with the path to each. It covers what is loaded,
so a schema's tables are found once the schema has been opened.
↑/↓ move between matches, enter goes to one and opens the path to it,
and esc puts the tree back as it was.
Query: ctrl+s saves, alt+s saves as, ctrl+w closes the tab,
ctrl+pgup/pgdn or alt+[/alt+] switch tabs, ctrl+e changes the context,
esc cancels a running query.
Results: enter opens the cell, esc stops fetching, the arrows or hjkl move, pgup/pgdn page, g/G jump to the
first or last row, home/end to the first or last column, y copies the
cell, Y copies the row, e exports the result. For a SQL Server batch with several results, [
and ] switch between them (the status shows [2/3]), and m shows the
batch's messages; y there copies them.
Outside the editor, tab cycles focus, ? shows the keys and q quits. The mouse focuses panes
and drags the borders between them; a double click on a border resets it.
Use shift+drag for the terminal's own text selection.
macos-option-as-alt.ctrl+enter as a plain Enter, and uses
alt+enter and alt+shift+arrows itself. Run with F5, resize with
ctrl+g then the arrows, or remap the keys.ctrl+enter needs a terminal that speaks the kitty keyboard protocol
(kitty, Ghostty, WezTerm, foot, recent Alacritty). rimor detects this and
shows ^⏎ in its hints only where it works; elsewhere they show F5.On first run rimor creates its configuration folder:
| Settings and connections | Session | |
|---|---|---|
| Linux, macOS | ~/.config/rimor | ~/.local/state/rimor |
| Windows | %APPDATA%\rimor | %LOCALAPPDATA%\rimor |
$XDG_CONFIG_HOME and $XDG_STATE_HOME take precedence when set.
config.toml is written with every default present but commented out;
uncomment a line to change it:
theme = "light" # "auto", "dark", "light" or "terminal"
icons = "plain" # "auto", "nerd" or "plain"
leader = "ctrl+b"
result_memory_mb = 2048 # memory a query's rows may take
script_rows = 50 # rows the explorer's select scripts take
check_updates = false # never ask GitHub for new releases
agent = false # no AI agent access (see AI agents)
[keys]
full_screen = ["alt+z", "leader z"] # replaces alt+f and leader f
run = ["ctrl+r", "f5"]
The template lists every action. Keys inside panes (editor, explorer, results) are not remappable yet.
SELECT, WITH, SHOW and the like, or containing
RETURNING, shows rows; anything else shows the rows affected. A mutating
statement never runs twice to find out. SQL Server batches are not
classified: the server reports what they produce, so DECLARE …; SELECT …
shows its rows and a batch that only writes shows the rows affected.
MySQL batches are not classified either: the first result with columns is
shown (SET @x := 1; SELECT … included), else the rows the last statement
affected.result_memory_mb (512 MB by
default, shared by all the results of a batch); fetching stops there and
keeps what arrived, and a batch says it was not read to its end. Spilling larger
results to disk is planned.. shows them.set-clipboard on. ctrl+v asks the terminal for the clipboard:
kitty and Ghostty ask you first, Alacritty needs osc52 = "CopyPaste",
and where the terminal does not answer, rimor pastes what it copied
itself. The terminal's own paste (ctrl+shift+v, cmd+v) always works.Pushing a version tag releases it:
git tag v0.2.0 && git push origin v0.2.0
release.yml tests the tagged commit, builds
the six archives, and publishes a GitHub Release with their checksums; then
aur-publish.yml builds the rimor and
rimor-bin packages from the templates in packaging/aur/ and pushes them
to the AUR. A tag with a hyphen (v0.2.0-rc.1) is published on GitHub as a
prerelease and skips the AUR. The AUR job needs the AUR_SSH_PRIVATE_KEY,
AUR_USERNAME and AUR_EMAIL secrets; it can be re-run for an existing tag
from the Actions tab.
go test ./...
The SQLite tests always run. The server tests run when a connection string is given:
RIMOR_TEST_POSTGRES='postgres://postgres@localhost:5432/postgres?sslmode=disable' \
RIMOR_TEST_POSTGRES_DB=warehouse \
RIMOR_TEST_SQLSERVER='sqlserver://user:pass@host?database=db&TrustServerCertificate=true' \
RIMOR_TEST_MYSQL='root:pass@tcp(127.0.0.1:33306)/rimor_test' \
RIMOR_TEST_MARIADB='root:pass@tcp(127.0.0.1:33307)/rimor_test' \
go test ./...
RIMOR_TEST_POSTGRES_DB names a second database on the same server, for the
tests that switch databases. The SQL Server tests only read data and use temp
tables. The MySQL and MariaDB tests create and drop databases named
rimor_*; throwaway servers will do:
docker run -d --name rimor-mysql -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=rimor_test -p 127.0.0.1:33306:3306 mysql:8.4
docker run -d --name rimor-mariadb -e MARIADB_ROOT_PASSWORD=pass -e MARIADB_DATABASE=rimor_test -p 127.0.0.1:33307:3306 mariadb:11
| Package | Contents |
|---|---|
cmd/rimor | entry point |
internal/ui | panes, layout, dialogs, key handling, agent tool calls |
internal/agent | rimor mcp and the socket to the running rimor |
internal/editor | the SQL editor and highlighting |
internal/db | connections, catalog queries per driver, execution |
internal/config | config.toml and the bindable actions |
internal/paths | where files live on each platform |
[ and ] switch between them) and, with m, its messages in
order: PRINT, SET STATISTICS output, each statement's rows affected,
and errors where they happened. Scripts split into batches by GO lines
run as in SQL Server Management Studio: each batch in turn, GO 5
repeating one, errors on the script's own line numbers.enter on a result cell opens its full value,
selected for copying. When the result comes from one table and includes
its key, the value can be edited there: rimor shows the UPDATE it will
run, changes only that row, and refuses if the row changed since it was
loaded.USE, SET,
temp tables and open transactions carry over between runs. A tab inside a
transaction says so in its status line (in transaction, or failed transaction when only a rollback can end it). Closing the tab, changing
its context, quitting, or disconnecting, editing or deleting its
connection first asks whether to commit or roll back; a failed
transaction can only be rolled back. The connection is then closed,
never handed to another tab or the explorer. If the connection is lost
inside a transaction, rimor says so: the server has rolled it back, and
the statement is not run again outside it.alt+a.F1 lists the keys that apply where you are, with
your own bindings, and filters them as you type.alt shortcut an alternative for terminals that keep alt for themselves.