OrmAI
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.
Why OrmAI?
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.
Pick Your Stack
| 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 |
Python Quick Start
# 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
TypeScript Quick Start
# Core (required)
npm install @ormai/core
# Choose your ORM adapter
npm install @ormai/prisma
import { 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);
What You Get Out of the Box
| 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 |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ 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.
Documentation
docs.neullabs.com/ormai — Full guides, API reference, and examples.
Installation
Python
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]
TypeScript / Node.js
# 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 helpers
Policy Configuration
Python
from 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()
)
TypeScript
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)
Agent Framework Integrations
| 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 |
Supported ORMs
| ORM | Python | TypeScript |
|---|---|---|
| SQLAlchemy | ✅ | — |
| Prisma | — | ✅ |
| Drizzle | — | ✅ |
| TypeORM | — | ✅ |
| SQLModel | ✅ | — |
| Django ORM | ✅ | — |
| Tortoise ORM | ✅ | — |
| Peewee | ✅ | — |
Benchmark: OrmAI vs Text-to-SQL
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 20
Examples
examples/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.
Contributing
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 test
See contributing guide for development setup and guidelines.
Documentation · GitHub · PyPI · npm
MIT License · Built by Neul Labs
Metadata
Release files for ormai 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ormai-0.2.1.tar.gz | 640.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ormai-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 829.2 kB
Release files / ormai-0.2.1.tar.gz
| Download URL | ormai-0.2.1.tar.gz |
|---|---|
| Size | 640.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
52465389c0a232a02a810cfac580ca0ee68acc0fdbc334f58e219775dbf91255
|
|
BLAKE2b-256 checksum How to use checksums |
b3680c7d5254db7854877d2f69d40e5f9b41a92b283bddbfe4333bd6fdcf65c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / ormai-0.2.1-py3-none-any.whl
| Download URL | ormai-0.2.1-py3-none-any.whl |
|---|---|
| Size | 189.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d5290be57ed9c42e1ad9d806a46dd11b85e59e23fc5567d1853623cd00f0809c
|
|
BLAKE2b-256 checksum How to use checksums |
083efe4f12fda37a51bfff1129ff1ba4cfefe274829e1e9ee1871dfd17a9fb8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|