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.
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:
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:
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:
Repositories expose typed CRUD operations. They do not expose raw SQL; all queries go through Drizzle’s query builder.