Codumentor logo Codumentor

Database Plugin

Gives the agent general SQL tools — list connections, list tables, describe a table, run a read-only query, and run a gated write — against one or more configured databases. Each connection picks its own backend: a native Python driver or an external database CLI. Engines: Postgres, MySQL/MariaDB, Oracle, SQL Server, plus SQLite.

Switchable backends

A connection's mode decides how it talks to the database:

modeBehaviour
nativeUse the engine's Python driver.
cliShell out to the engine's command-line tool.
auto (default)Native if the driver is importable, otherwise the CLI.
EngineNative driverCLI fallbackDefault port
Postgres (postgres, also postgresql / pg)pg8000psql5432
MySQL / MariaDB (mysql, also mariadb)PyMySQLmysql3306
Oracle (oracle, also oracledb)oracledb (thin mode)—1521
SQL Server (sqlserver, also mssql)python-tdsgo-sqlcmd1433
SQLite (sqlite)stdlib sqlite3——

The four native drivers ship with Codumentor (pure Python — no libpq, Oracle Instant Client, or ODBC). They are imported only when a connection uses them, so a missing driver does not prevent the plugin from loading; mode: auto then falls back to the CLI.

Use the CLI path when you prefer not to use the bundled driver, or for cases the pure-Python drivers handle poorly — most notably SQL Server with Azure AD / TDS 8.0, where go-sqlcmd (a single static MIT binary) is the better choice. Oracle thin mode covers Oracle fully, so no Oracle CLI ships.

Native connections support bound params; CLI connections do not (use mode: native for parameterized queries).

Tools

ToolApprovalPurpose
sql_list_connectionsnoneList configured connections (name, engine, host, database, read-only). Touches no database.
sql_list_tablesnoneExplore tables/views. Optional schema and pattern (case-insensitive name substring) filters; see below.
sql_describe_tablenoneColumn metadata (name, type, nullability, default).
sql_querynoneRun a read-only statement; rejects anything that isn't a single SELECT/WITH/EXPLAIN. Row-capped; results are JSON.
sql_executedatabase.executeRun a write/DDL statement. Permission-gated, and refused on read-only connections (no prompt).

When exactly one connection is configured, the connection argument is optional everywhere and defaults to it.

Who gets which half

Two gates, not one. target_agents (default all) decides whether the tools are offered at all; write_target_agents (default main) then decides who gets sql_execute.

By default a subagent can explore a schema and run read-only queries but cannot change data or DDL — the approval prompt sql_execute raises is meant for a human, and nobody is reading a subagent's tool calls as they happen. Set write_target_agents: all if subagents should also write. A connection's own read_only is the stricter guard and applies to every agent.

sql_query results come back as a JSON envelope — {"columns": [...], "rows": [...], "row_count": N, "truncated": bool} — rather than an ASCII table. When truncated is true, narrow the query.

Who gets the tools at all

target_agents decides which agent; access profiles decide which user. The whole sql_* family declares shared_credentials = True, because the connections it reaches are ones the operator configured — so a profile on a restricted capability policy (chat_only, qa_readonly) holds none of them unless you say otherwise:

access:
  profiles:
    office-assistant:
      repos: none
      capabilities: chat_only
      tools:
        allow: [sql_query, sql_list_tables]   # or: shared_credentials: true

This holds even for connections that resolve a per-user password_secret. The declaration is on the family rather than computed per connection for two reasons: connection is a per-call argument, so one tool object spans every configured connection and a mixed deployment has no single answer; and sql_list_connections discloses the inventory — which databases this deployment talks to — whoever can open them. A deployment whose connections really are all per-user says so once, with tools: {shared_credentials: true}.

Choosing the databases per conversation

The welcome screen shows a Databases selector under the repository/branch selector: one checkbox per connection, plus All / None. Whatever the user ticks is what the agent may query in that conversation:

The choice is enforced when the tool is called, not only in the prompt: a refused call fails before any approval prompt. The selector starts from the user's last choice, and when a conversation is opened it saves what it shows, so the screen and the agent always agree. A conversation that narrowed or switched off databases shows a DB: … banner above the transcript. A connection added to the config later is not added to existing selections, because a selection is an explicit list.

The selector and its routes (/ui/plugins/database/…) are offered only to users who get the SQL tools at all (the database.selection access feature, paired with the family's shared_credentials).

Schema exploration scales down, not up

sql_list_tables adapts its output so a huge catalog cannot silently swallow schemas:

The intended flow on big databases is therefore: counts overview → drill into one schema, or search by name fragment (pattern: "kivonat").

Configuration

plugins:
  - module: codumentor.plugins.database
    class: DatabasePlugin
    args:
      enabled: true
      target_agents: all          # main | subagent | all — the whole family
      write_target_agents: main   # same values, sql_execute only
      default_read_only: true     # per-connection default
      max_rows: 1000              # hard cap for sql_query
      statement_timeout: 30       # seconds
      default_selection: all      # all | none — before the user picks
      connections:
        - name: analytics         # logical handle the agent uses
          engine: postgres        # postgres | mysql | oracle | sqlserver | sqlite
          mode: auto              # native | cli | auto
          host: db.example.com
          port: 5432
          database: analytics
          user: reporting
          password_secret: pg_analytics_password   # per-user secret name
          read_only: true
        - name: warehouse
          engine: sqlserver
          mode: cli               # go-sqlcmd
          host: mssql.example.com
          port: 1433
          database: warehouse
          user: svc_reader
          password_secret: mssql_warehouse_password
          read_only: true

Load user_secrets alongside this plugin so passwords can resolve per user.

Plugin parameters

ParameterTypeDefaultDescription
enabledbooltrueMaster on/off.
target_agentsstringallWho gets the tools: main, subagent, all, or a subagent role name.
write_target_agentsstringmainSame values, applied to sql_execute only. Subagents keep the read half.
default_read_onlybooltrueApplied to any connection that omits read_only.
max_rowsint1000Hard cap for sql_query (and the name cap for filtered sql_list_tables).
statement_timeoutfloat30Per-statement timeout in seconds.
default_selectionstringallConnections a conversation may use before the user picks in the selector: all or none (opt-in).
connectionslist[]Named connections (see below). Names must be unique.

Connection parameters

ParameterTypeDefaultDescription
namestring(required)Handle the agent uses in tool calls.
enginestring(required)postgres, mysql, oracle, sqlserver, or sqlite (aliases above).
modestringautonative, cli, or auto.
hoststringlocalhostDatabase host.
portintengine defaultOmit to use the engine default.
databasestring—Database / service name. For SQLite this is the file path (:memory: if omitted).
userstring—Login user.
password_secretstring—Per-user secret name (preferred).
passwordstring—Shared credential; may contain ${secret:...}.
read_onlybooldefault_read_onlyWhen true, sql_execute is refused.
connect_kwargsmap{}Extra keyword arguments passed to the native driver (for example an Oracle dsn).

Credentials

Two models are supported, per connection:

  1. Per-user secret (preferred) — set password_secret: <name>. The config stores only the secret name; each user supplies their own password in Settings → Extensions → User Secrets, and tools authenticate as the calling user. The pane shows "DB password (<connection>) — needed by Databases".
  2. Shared service account — set password: ${secret:<name>} (a shared secret resolved server-side). Useful for a read-only reporting replica with a single account.

If a password_secret is declared but unset, tools return a clear, non-retryable message naming the secret — no connection attempt is made. A connection with neither field resolves to "no password" (works for SQLite, trusted/integrated auth, etc.).

Safety

Notes & limitations