Give your AI agents database access without the risk.
OrmAI wraps your existing ORM models in a policy-enforced runtime. Your agents get typed tools for querying and writing data — while you keep control over what they can see and do. No raw SQL. No prompt injection into your database. Just safe, auditable, tenant-scoped database tools.
Available for Python and TypeScript/Node.js.
Building AI agents that interact with your database? You have probably thought about:
- "What if the agent reads sensitive data?" → Field-level policies hide or mask PII automatically.
- "What if it runs wild queries?" → Query budgets and row limits prevent runaway costs.
- "How do I audit what it did?" → Every operation is logged with full context.
- "What about multi-tenant isolation?" → Tenant scoping is built-in, not bolted on.
- "Which ORM do we use?" → Works with SQLAlchemy, Prisma, Drizzle, TypeORM, Tortoise, Django, SQLModel, and Peewee.
OrmAI solves these at the ORM layer — not the prompt layer.
| Python | TypeScript / Node.js | |
|---|---|---|
| Package | pip install ormai |
npm install @ormai/core |
| ORMs | SQLAlchemy, Tortoise, Django, SQLModel, Peewee | Prisma, Drizzle, TypeORM |
| Integrations | OpenAI, LangChain, LlamaIndex, MCP, FastAPI | Vercel AI SDK, LangChain.js, OpenAI, Anthropic, LlamaIndex.ts, Mastra, MCP |
| Quickstart | ormai.quickstart |
@ormai/utils |
| Docs | Python Guide | TS Guide |
# With your ORM of choice
pip install ormai[sqlalchemy]
# or
pip install ormai[prisma]from ormai.quickstart import mount_sqlalchemy
from ormai.utils import DEFAULT_DEV
# Your existing SQLAlchemy models + session
toolset = mount_sqlalchemy(
engine=engine,
session_factory=Session,
policy=DEFAULT_DEV
)
# Done. Your agent now has: db.query, db.get, db.aggregate, db.describe_schema# Core (required)
npm install @ormai/core
# Choose your ORM adapter
npm install @ormai/prismaimport { PrismaClient } from '@prisma/client';
import { PrismaAdapter } from '@ormai/prisma';
import { PolicyBuilder, createContext } from '@ormai/core';
import { createGenericTools } from '@ormai/tools';
const prisma = new PrismaClient();
const adapter = new PrismaAdapter({ prisma });
const schema = await adapter.introspect();
const policy = new PolicyBuilder('prod')
.registerModels(['Customer', 'Order'])
.tenantScope('tenantId')
.denyFields('*password*')
.maskFields('*email*')
.build();
const tools = createGenericTools({ adapter, policy, schema });
const ctx = createContext({
tenantId: 'tenant-123',
userId: 'user-456',
db: prisma,
roles: ['admin'],
});
// Your agent now has safe database tools
const result = await tools[0].execute({
model: 'Order',
where: [{ field: 'status', op: 'eq', value: 'pending' }],
take: 10,
}, ctx);| Feature | What It Does |
|---|---|
| Read-safe tools | db.query, db.get, db.aggregate, db.describe_schema — no raw SQL |
| Write-safe tools | db.create, db.update, db.delete, db.bulk_update — gated by policy |
| Field-level policies | Hide passwords, mask emails, deny sensitive columns automatically |
| Tenant scoping | .tenantScope('tenant_id') auto-filters every query per user |
| Query budgets | Max rows, max includes depth, statement timeouts per model |
| Audit logging | Every call logged with principal, tenant, trace ID, input, output |
| Human approval gates | Require reason or approval for writes on sensitive models |
| Schema introspection | Auto-discovers models, fields, relations, primary keys |
| Multi-framework | LangChain, OpenAI, Vercel AI SDK, LlamaIndex, Mastra, FastAPI, MCP |
┌─────────────────────────────────────────────────────────────┐
│ Your Agent │
└──────────────────────────┬──────────────────────────────────┘
│ calls tools
┌──────────────────────────▼──────────────────────────────────┐
│ OrmAI Runtime │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐│
│ │ Policy │ │ Audit │ │ Tenant Scope ││
│ │ Enforcer │ │ Logger │ │ Filter ││
│ └─────────────┘ └─────────────┘ └─────────────────────┘│
└──────────────────────────┬──────────────────────────────────┘
│ parameterized queries only
┌──────────────────────────▼──────────────────────────────────┐
│ Your ORM (SQLAlchemy / Prisma / Drizzle / ...) │
└─────────────────────────────────────────────────────────────┘
OrmAI sits between your agent and your ORM. It compiles agent requests into type-safe ORM queries, enforces policies, logs everything, and returns structured results. Your database never sees raw SQL from the agent.
docs.neullabs.com/ormai — Full guides, API reference, and examples.
pip install ormai[sqlalchemy]
pip install ormai[tortoise]
pip install ormai[peewee]
pip install ormai[django]
pip install ormai[sqlmodel]
# Or all adapters
pip install ormai[all]# Core (required)
npm install @ormai/core
# ORM adapters
npm install @ormai/prisma
npm install @ormai/drizzle
npm install @ormai/typeorm
# Optional packages
npm install @ormai/tools # Generic database tools
npm install @ormai/store # Audit logging
npm install @ormai/mcp # MCP server
npm install @ormai/integrations # Framework adapters
npm install @ormai/utils # PolicyBuilder and helpersfrom ormai.utils import PolicyBuilder, DEFAULT_PROD
policy = (
PolicyBuilder(DEFAULT_PROD)
.register_models([Customer, Order])
.deny_fields("*password*", "*secret*", "*token*")
.mask_fields(["email", "phone"])
.tenant_scope("tenant_id")
.enable_writes(models=["Order"], require_reason=True)
.build()
)import { PolicyBuilder } from '@ormai/core';
const policy = new PolicyBuilder('prod')
.registerModels(['Customer', 'Order', 'Product'])
.tenantScope('tenantId')
.denyFields('*password*')
.maskFields('*email*')
.allowRelations('Order', ['customer', 'items'])
.enableWrites(['Order'], {
allowCreate: true,
allowUpdate: true,
allowDelete: false,
maxAffectedRows: 10,
})
.defaultBudgetConfig({
maxRows: 100,
maxIncludesDepth: 2,
statementTimeoutMs: 5000,
})
.build();Presets: DEFAULT_DEV (permissive), DEFAULT_INTERNAL (moderate), DEFAULT_PROD (strict)
| Framework | Python Package | TypeScript Package |
|---|---|---|
| OpenAI | ormai |
@ormai/integrations |
| LangChain | ormai |
@ormai/integrations |
| Vercel AI SDK | — | @ormai/integrations |
| LlamaIndex | ormai |
@ormai/integrations |
| Mastra | — | @ormai/integrations |
| Anthropic | — | @ormai/integrations |
| FastAPI | ormai |
— |
| MCP | ormai |
@ormai/mcp |
| ORM | Python | TypeScript |
|---|---|---|
| SQLAlchemy | ✅ | — |
| Prisma | — | ✅ |
| Drizzle | — | ✅ |
| TypeORM | — | ✅ |
| SQLModel | ✅ | — |
| Django ORM | ✅ | — |
| Tortoise ORM | ✅ | — |
| Peewee | ✅ | — |
We benchmarked against the Spider dataset — 1034 natural language queries:
| Metric | OrmAI | Text-to-SQL |
|---|---|---|
| SQL Injection possible | No | Yes |
| Unsafe ops executed | 0 | 23 |
| Full audit trail | Yes | No |
# Try it yourself
pip install ormai[benchmark]
python examples/spider_demo.py run --limit 20examples/spider_demo.py— Benchmark demoexamples/fastapi-sqlalchemy/— FastAPI + SQLAlchemy integrationormai-ts/— TypeScript monorepo with Prisma, Drizzle, and TypeORM examples
More examples at docs.neullabs.com/ormai/examples.
git clone https://github.com/neul-labs/ormai.git
cd ormai
# Python
uv sync --dev
uv run pytest
# TypeScript
cd ormai-ts
npm install
npm run build
npm run testSee contributing guide for development setup and guidelines.
Documentation · GitHub · PyPI · npm
MIT License · Built by Neul Labs