> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kavachos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prisma adapter

> Query every KavachOS table through an existing PrismaClient via @kavachos/prisma. Supports Prisma transactions without requiring Drizzle as a second ORM client.

KavachOS ships a Drizzle-based database layer by default. If your project already uses [Prisma](https://www.prisma.io), the `@kavachos/prisma` adapter lets you query every KavachOS table through your existing `PrismaClient`, no Drizzle installation required.

<Info>
  The Prisma adapter is a standalone query layer. It does not replace or wrap
  the core KavachOS instance. Use it to read and write KavachOS data from
  the parts of your codebase that already work with Prisma.
</Info>

## When to use it

* You have an existing Prisma project and want to avoid running two ORM clients.
* You need to query KavachOS tables inside Prisma transactions that span your own models.
* You prefer generated Prisma types over Drizzle's schema for editor autocomplete.
* Your team finds Prisma's DSL easier to maintain than raw SQL DDL.

The adapter covers agents, users, sessions, audit logs, permissions, delegation chains, OAuth, API keys, organizations, trust scores, approval requests, and every other KavachOS table.

## Installation

```bash theme={"system"}
pnpm add @kavachos/prisma @prisma/client
```

The adapter has no runtime dependency on `kavachos` itself, `@prisma/client` is the only peer dep.

## Setup

<Steps>
  <Step>
    ### Add the KavachOS models to your Prisma schema

    Copy the models from `node_modules/@kavachos/prisma/src/schema.prisma` into your `prisma/schema.prisma`, or use it as a reference to add only the tables you need.

    The schema targets Postgres by default. Switch the `datasource` provider to `sqlite` or `mysql` as appropriate.

    ```prisma theme={"system"}
    // prisma/schema.prisma
    generator client {
      provider = "prisma-client-js"
    }

    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }

    // ... your existing models ...

    model KavachUser {
      id                 String    @id
      email              String    @unique
      name               String?
      banned             Boolean   @default(false)
      createdAt          DateTime  @map("created_at")
      updatedAt          DateTime  @map("updated_at")
      // ... (see full schema in @kavachos/prisma/src/schema.prisma)

      @@map("kavach_users")
    }

    model KavachAgent {
      id          String    @id
      ownerId     String    @map("owner_id")
      name        String
      type        String
      status      String    @default("active")
      tokenHash   String    @map("token_hash")
      tokenPrefix String    @map("token_prefix")
      expiresAt   DateTime? @map("expires_at")
      createdAt   DateTime  @map("created_at")
      updatedAt   DateTime  @map("updated_at")

      @@map("kavach_agents")
    }

    // ... add remaining models from schema.prisma ...
    ```
  </Step>

  <Step>
    ### Run migrations

    ```bash theme={"system"}
    npx prisma migrate dev --name add-kavachos
    ```

    Or push to an existing database without a migration file:

    ```bash theme={"system"}
    npx prisma db push
    ```
  </Step>

  <Step>
    ### Create the adapter

    ```typescript theme={"system"}
    import { PrismaClient } from '@prisma/client';
    import { createPrismaAdapter } from '@kavachos/prisma';

    const prisma = new PrismaClient();
    export const kavachDb = createPrismaAdapter(prisma);
    ```
  </Step>
</Steps>

## Usage

### Agent operations

```typescript theme={"system"}
import { kavachDb } from './lib/kavach-db';

// Look up an agent by ID
const agent = await kavachDb.findAgentById('agent-123');

// Look up by token hash (for auth middleware)
const agent = await kavachDb.findAgentByTokenHash(tokenHash);

// List all active agents owned by a user
const agents = await kavachDb.listAgents({
  ownerId: 'user-456',
  status: 'active',
});

// Create an agent
const agent = await kavachDb.createAgent({
  id: crypto.randomUUID(),
  ownerId: 'user-456',
  name: 'my-agent',
  type: 'autonomous',
  tokenHash: hash,
  tokenPrefix: prefix,
  createdAt: new Date(),
  updatedAt: new Date(),
});

// Revoke an agent
await kavachDb.updateAgent('agent-123', { status: 'revoked' });
```

### User operations

```typescript theme={"system"}
// Find by email (for sign-in)
const user = await kavachDb.findUserByEmail('alice@example.com');

// Create a user
const user = await kavachDb.createUser({
  id: crypto.randomUUID(),
  email: 'alice@example.com',
  name: 'Alice',
  createdAt: new Date(),
  updatedAt: new Date(),
});

// Update user (e.g., link Stripe customer)
await kavachDb.updateUser(userId, {
  stripeCustomerId: 'cus_abc123',
});
```

### Session management

```typescript theme={"system"}
// Create a session
const session = await kavachDb.createSession({
  id: crypto.randomUUID(),
  userId: 'user-456',
  expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
  createdAt: new Date(),
});

// Validate a session
const session = await kavachDb.findSessionById(sessionId);
if (!session || session.expiresAt < new Date()) {
  throw new Error('Session expired');
}

// Clean up expired sessions
const deleted = await kavachDb.deleteExpiredSessions();
```

### Audit log queries

```typescript theme={"system"}
// Query recent actions for an agent
const logs = await kavachDb.queryAuditLogs({
  agentId: 'agent-123',
  since: new Date(Date.now() - 24 * 60 * 60 * 1000),
  limit: 50,
});

// Query denied actions for investigation
const denials = await kavachDb.queryAuditLogs({
  userId: 'user-456',
  result: 'denied',
  since: new Date('2025-01-01'),
});

// Write an audit log entry
await kavachDb.createAuditLog({
  id: crypto.randomUUID(),
  agentId: 'agent-123',
  userId: 'user-456',
  action: 'execute',
  resource: 'mcp:github:create_issue',
  result: 'allowed',
  durationMs: 42,
  timestamp: new Date(),
});
```

### Permissions

```typescript theme={"system"}
// Get all permissions for an agent
const perms = await kavachDb.findPermissionsByAgentId('agent-123');

// Grant a permission
await kavachDb.createPermission({
  id: crypto.randomUUID(),
  agentId: 'agent-123',
  resource: 'mcp:github:*',
  actions: ['read', 'write'],
  createdAt: new Date(),
});

// Revoke all permissions for an agent
await kavachDb.deletePermissionsByAgentId('agent-123');
```

### Transactions

The adapter wraps Prisma's `$transaction` to let you compose KavachOS operations with your own Prisma queries:

```typescript theme={"system"}
import { PrismaClient } from '@prisma/client';
import { createPrismaAdapter } from '@kavachos/prisma';

const prisma = new PrismaClient();
const kavachDb = createPrismaAdapter(prisma);

// KavachOS operations inside a transaction
await kavachDb.transaction(async (tx) => {
  const agent = await tx.createAgent({ ... });
  await tx.createPermission({ agentId: agent.id, ... });
});

// Mix with your own Prisma models
await prisma.$transaction(async (tx) => {
  const kavach = createPrismaAdapter(tx);
  await kavach.createAgent({ ... });
  // Your own model:
  await tx.subscription.create({ data: { ... } });
});
```

### Trust scores

```typescript theme={"system"}
// Get the trust score for an agent
const trust = await kavachDb.findTrustScore('agent-123');
console.log(trust?.level); // "trusted" | "limited" | ...

// Upsert after recomputing
await kavachDb.upsertTrustScore({
  agentId: 'agent-123',
  score: 85,
  level: 'trusted',
  factors: { successRate: 0.99, age: 30 },
  computedAt: new Date(),
});
```

### Approval requests

```typescript theme={"system"}
// List pending approvals for a human to review
const pending = await kavachDb.listPendingApprovals('agent-123');

// Approve a request
await kavachDb.updateApprovalRequest(requestId, {
  status: 'approved',
  respondedAt: new Date(),
  respondedBy: 'user-456',
});
```

## Migration from Drizzle

If you started with the built-in Drizzle backend and want to switch to Prisma:

1. Keep the same table names, all KavachOS tables use the `kavach_` prefix and the same column names in both Drizzle and Prisma.
2. Run `npx prisma introspect` against your existing database to generate a Prisma schema from the Drizzle-created tables.
3. Replace calls to the Drizzle `db` directly with `createPrismaAdapter(prisma)`.
4. Set `database.skipMigrations: true` in `createKavach(...)` if the core KavachOS instance is still used for other features (agents, MCP, etc.), so Drizzle does not conflict with Prisma.

```typescript theme={"system"}
const kavach = await createKavach({
  database: {
    provider: 'postgres',
    url: process.env.DATABASE_URL,
    skipMigrations: true, // Prisma owns the schema now
  },
});

// Use the Prisma adapter for direct table access
const db = createPrismaAdapter(prisma);
```

<Warning>
  The core KavachOS instance (`createKavach`) still uses Drizzle internally
  for agent creation, authorization, MCP flows, and other built-in features.
  `@kavachos/prisma` gives you a Prisma-native way to read and write the same
  tables, it does not replace `createKavach`.
</Warning>

## Reference schema

The full reference schema is in `node_modules/@kavachos/prisma/src/schema.prisma`. It includes all 30+ KavachOS models with correct column mappings, indexes, and default values.

Every model name follows `KavachPascalCase` and maps to a `kavach_snake_case` table, keeping your Prisma namespace clean and your SQL tables clearly scoped.
