Database

Read and write access to SQL databases with privilege separation via separate engines.

DatabaseContextProvider gives agents read/write access to any SQL database via SQLAlchemy. Two tools: query_database for reads, update_database for writes.

Prerequisites

1uv pip install -U kern-ai sqlalchemy
2# Plus your database driver:
3uv pip install -U psycopg2-binary # PostgreSQL
4uv pip install -U pymysql # MySQL

Example

1from sqlalchemy import create_engine
2from kern.agent import Agent
3from kern.models.openai import OpenAIResponses
4from kern.context.database import DatabaseContextProvider
5
6# Two engines: one read-only, one writable
7readonly_engine = create_engine("postgresql://reader:pass@localhost/mydb")
8sql_engine = create_engine("postgresql://writer:pass@localhost/mydb")
9
10db = DatabaseContextProvider(
11 sql_engine=sql_engine,
12 readonly_engine=readonly_engine,
13 schema="public",
14)
15
16agent = Agent(
17 model=OpenAIResponses(id="gpt-5.4"),
18 tools=db.get_tools(),
19 instructions=db.instructions(),
20)
21
22agent.print_response("How many orders were placed last month?")
Warning

Both engines are required. The read sub-agent uses readonly_engine exclusively. Even if the model tries to run a write query, the database connection physically cannot execute it.

Provider Params

ParameterTypeDefaultDescription
sql_engineEnginerequiredSQLAlchemy engine for writes.
readonly_engineEnginerequiredSQLAlchemy engine for reads. Use a read replica or a user with SELECT-only permissions.
schemastr | NoneNoneScope queries to a specific schema.
idstr"database"Provider ID. Tools become query_<id> and update_<id>.
namestr | NoneNoneDisplay name. Defaults to id ("database").
read_instructionsstr | NoneNoneCustom instructions for the read sub-agent.
write_instructionsstr | NoneNoneCustom instructions for the write sub-agent.
modeContextModedefaultTool exposure mode. See Architecture.
modelModel | NoneNoneModel for the sub-agents. Defaults to Kern's default model.
readboolTrueExpose query_database tool.
writeboolTrueExpose update_database tool.

Tools Exposed

ToolDescription
query_databaseRun SELECT queries, describe tables, explore schema. Uses readonly_engine.
update_databaseRun INSERT/UPDATE/DELETE queries. Uses sql_engine.

Privilege Separation

The read and write sub-agents use separate database connections:

1query_database readonly_engine read replica / SELECT-only user
2update_database sql_engine writable connection

This is infrastructure-level protection. The read sub-agent's connection cannot execute writes regardless of what SQL the model generates.

Multiple Databases

Use different id values to expose multiple databases:

1orders_db = DatabaseContextProvider(
2 id="orders",
3 sql_engine=orders_write_engine,
4 readonly_engine=orders_read_engine,
5)
6
7inventory_db = DatabaseContextProvider(
8 id="inventory",
9 sql_engine=inventory_write_engine,
10 readonly_engine=inventory_read_engine,
11)
12
13agent = Agent(
14 model=...,
15 tools=[*orders_db.get_tools(), *inventory_db.get_tools()],
16)
17# Agent sees: query_orders, update_orders, query_inventory, update_inventory

Read-only Mode

1db = DatabaseContextProvider(
2 sql_engine=engine,
3 readonly_engine=readonly_engine,
4 write=False,
5)
6# Agent only sees query_database

Cookbook

database

Database Context Provider

Read/write with separate engines