Skip to main content
The vault is Grind’s database layer. It lives in packages/core/src/vault/. The underlying storage is SQLite via libsql, with optional Turso cloud sync.

Storage Location

By default, the vault database is at ~/.grind/vault.db. This can be overridden via GRIND_VAULT_PATH.

Encryption

The vault is encrypted at rest using libsql’s AES encryption extension. The key is stored at ~/.grind/.key and set via GRIND_ENCRYPTION_KEY.
const client = createClient({
  url: `file:${vaultPath}/vault.db`,
  encryptionKey: config.encryptionKey,
});
The encryption key is required to open the vault. If you lose it, your data is unrecoverable. Back it up to a password manager.

Turso Sync

For optional cloud backup and multi-device sync, configure a Turso database:
TURSO_DATABASE_URL=libsql://your-db.turso.io
TURSO_AUTH_TOKEN=your-token
With these set, libsql operates in embedded replica mode. The local SQLite file is the primary, syncing bidirectionally with Turso.

Migrations

Migrations are SQL files in packages/core/drizzle/. The migration runner in vault/client.ts applies them on startup. The standard Drizzle migration runner uses Postgres-compatible syntax for migration tracking. Grind replaces it with a custom SQLite-compatible runner that uses a simple drizzle_migrations table. To generate a new migration after schema changes:
bun run db:generate
bun run db:migrate   # apply locally
bun run db:push      # push to Turso (if configured)

Schema

13 tables defined with Drizzle ORM in vault/schema.ts: users, quests, quest_logs, proofs, skills, rituals, signals, forge_rules, forge_runs, trust_log, companion_settings, conversations, messages. All timestamps are Unix epoch integers; primary keys are UUIDs.

Repository Pattern

All database access goes through repository objects. Each domain entity has a corresponding repository:
import { createVaultClient } from "@grindxp/core/vault";

const { db } = await createVaultClient(config);

// Repositories
const questRepo = createQuestRepository(db);
const skillRepo = createSkillRepository(db);
const userRepo = createUserRepository(db);
const companionRepo = createCompanionRepository(db);
const forgeRepo = createForgeRepository(db);
Repositories expose typed CRUD operations. They do not expose raw SQL; all queries go through Drizzle’s query builder.