> ## 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.

# Database setup

> Configure KavachOS with SQLite, Postgres, MySQL, or Cloudflare D1. Covers connection setup, migration, WAL mode for SQLite, and skipping auto-migrations.

KavachOS uses [Drizzle ORM](https://orm.drizzle.team) under the hood. You pick a provider and pass the connection URL; KavachOS handles the rest.

## Choosing a provider

| Provider | Best for                                                       |
| -------- | -------------------------------------------------------------- |
| SQLite   | Local dev, single-server deploys, serverless edge (with Turso) |
| Postgres | Production, high-concurrency, multi-tenant                     |
| MySQL    | Existing MySQL infrastructure                                  |

## Setup

<Tabs>
  <Tab title="SQLite">
    SQLite is the default for development. No peer dependencies beyond `better-sqlite3`, which ships with `kavachos`.

    ```typescript theme={"system"}
    import { createKavach } from 'kavachos';

    const kavach = await createKavach({
      database: {
        provider: 'sqlite',
        url: './kavach.db',
      },
    });
    ```

    For in-memory SQLite (tests and CI), use `:memory:` as the URL:

    ```typescript theme={"system"}
    const kavach = await createKavach({
      database: {
        provider: 'sqlite',
        url: ':memory:',
      },
    });
    ```

    KavachOS enables WAL mode and foreign keys automatically:

    ```sql theme={"system"}
    PRAGMA journal_mode = WAL;
    PRAGMA foreign_keys = ON;
    ```
  </Tab>

  <Tab title="Postgres">
    Install the `pg` peer dependency:

    ```bash theme={"system"}
    npm install pg
    npm install --save-dev @types/pg
    ```

    ```typescript theme={"system"}
    import { createKavach } from 'kavachos';

    const kavach = await createKavach({
      database: {
        provider: 'postgres',
        url: process.env.DATABASE_URL!,
        // postgresql://user:password@host:5432/dbname
      },
    });
    ```

    KavachOS uses `drizzle-orm/node-postgres` with a connection pool via `pg.Pool`. The `pg` package is loaded with a dynamic import, so it stays an optional peer dep.
  </Tab>

  <Tab title="MySQL">
    Install the `mysql2` peer dependency:

    ```bash theme={"system"}
    npm install mysql2
    ```

    ```typescript theme={"system"}
    import { createKavach } from 'kavachos';

    const kavach = await createKavach({
      database: {
        provider: 'mysql',
        url: process.env.DATABASE_URL!,
        // mysql://user:password@host:3306/dbname
      },
    });
    ```

    KavachOS uses `drizzle-orm/mysql2` with a connection pool. `mysql2` is loaded via dynamic import and stays an optional peer dep.
  </Tab>
</Tabs>

## Auto-migration

By default, KavachOS calls `CREATE TABLE IF NOT EXISTS` for all its tables on startup. This means your database is always ready to use without any manual migration step.

To disable this (e.g. when you manage migrations externally with Flyway, Liquibase, or `drizzle-kit push`), set `skipMigrations: true`:

```typescript theme={"system"}
database: {
  provider: 'postgres',
  url: process.env.DATABASE_URL!,
  skipMigrations: true,
},
```

<Warning>
  When `skipMigrations: true`, you are responsible for keeping the schema in sync. KavachOS will fail at runtime if expected tables or columns are missing.
</Warning>

## Schema overview

KavachOS creates the following tables in your database:

| Table                              | Purpose                                                |
| ---------------------------------- | ------------------------------------------------------ |
| `kavach_users`                     | Human user identities, synced from your auth provider  |
| `kavach_tenants`                   | Multi-tenant isolation                                 |
| `kavach_agents`                    | AI agent identities (the core entity)                  |
| `kavach_permissions`               | Per-agent resource+action permissions with constraints |
| `kavach_delegation_chains`         | Agent-to-agent delegation records                      |
| `kavach_audit_logs`                | Immutable log of every agent action                    |
| `kavach_rate_limits`               | Per-agent call-rate counters                           |
| `kavach_mcp_servers`               | Registered MCP servers                                 |
| `kavach_sessions`                  | KavachOS-managed human user sessions                   |
| `kavach_oauth_clients`             | OAuth 2.1 client registrations (RFC 7591)              |
| `kavach_oauth_access_tokens`       | Issued access and refresh tokens                       |
| `kavach_oauth_authorization_codes` | Short-lived PKCE authorization codes                   |
| `kavach_agent_cards`               | A2A capability discovery cards                         |
| `kavach_approval_requests`         | CIBA async approval flow records                       |
| `kavach_trust_scores`              | Graduated autonomy trust scores per agent              |
| `kavach_budget_policies`           | Token and call budget caps per agent/user/tenant       |

All table and column names use `snake_case`. All IDs are `text` (UUID or CUID2). Timestamps are stored as Unix seconds integers.

## Peer dependencies

| Provider | Required package                     |
| -------- | ------------------------------------ |
| SQLite   | `better-sqlite3` (bundled with core) |
| Postgres | `pg`                                 |
| MySQL    | `mysql2`                             |

KavachOS uses dynamic imports for Postgres and MySQL drivers so they remain optional. You will get a clear error message at startup if the required package is missing:

```
KavachOS: provider "postgres" requires the "pg" package.
Install it with: npm install pg
```

## Testing with in-memory SQLite

Use `:memory:` for fast, isolated tests that need no setup or teardown:

```typescript theme={"system"}
import { createKavach } from 'kavachos';
import { describe, beforeEach, it } from 'vitest';

let kavach: Awaited<ReturnType<typeof createKavach>>;

beforeEach(async () => {
  kavach = await createKavach({
    database: { provider: 'sqlite', url: ':memory:' },
    agents: { enabled: true },
  });
});

it('creates an agent', async () => {
  const agent = await kavach.agent.create({
    ownerId: 'user_1',
    name: 'Test Agent',
    type: 'autonomous',
    permissions: [],
  });

  expect(agent.id).toBeDefined();
});
```

Each `createKavach()` call with `:memory:` gets a completely isolated database, so tests never share state.
