persistence-drift

persistence-drift is a skill for Claude Code from zakariaf/Flutter-Skills. It costs 218 tokens per session (4,491 once invoked), scanned A, original, MIT.

A set of rules for storing app data on the device with Drift, a Dart database library built on SQLite. It keeps database code in one layer and exposes ordinary data objects to the rest of the app.

In plain words
What is it for?
Use it when designing SQLite tables, database access objects, repositories, transactions, indexes, migrations, or local backups.
Why use it?
It helps data survive app crashes, reboots, and process restarts while reducing invalid records, unsafe updates, and fragile backups.

Skill for Claude Code

Written for Claude Code: shipped in a Claude Code plugin.

Part of the flutter plugin — 40 skills shipped together

Good fit Use it when designing SQLite tables, database access objects, repositories, transactions, indexes, migrations, or local backups.

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/zakariaf/flutter-skills/persistence-drift
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Any agent
npx skills add zakariaf/Flutter-Skills --skill persistence-drift
Clone the repo
git clone --depth 1 https://github.com/zakariaf/Flutter-Skills

Made for: Claude Code.

Or install flutter, the plugin that ships this one along with the rest of its 40 skills.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for persistence-drift

README.md
[![agentmods](https://agentmods.dev/badge/skills/zakariaf/flutter-skills/persistence-drift.svg)](https://agentmods.dev/skills/zakariaf/flutter-skills/persistence-drift)
Your own site
<a href="https://agentmods.dev/skills/zakariaf/flutter-skills/persistence-drift"><img src="https://agentmods.dev/badge/skills/zakariaf/flutter-skills/persistence-drift.svg" alt="Measured on agentmods" height="20"></a>
Per session 218 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 4,491 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00218 $0.04491
Opus 5 $0.00109 $0.02246
Sonnet 5 $0.00044 $0.00898
Haiku 4.5 $0.00022 $0.00449

Measured 7d ago against content hash fbc122997aa7, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-07, from the pricing page.

Security

Grade A, and why

persistence-drift scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 7d ago.

The scan reads SKILL.md. This mod also ships 2 executable files (scripts/check-drift-confinement.sh, scripts/check-persistence-bans.sh), listed below but not scanned — reading those needs a real analyzer, not pattern matching.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

skills/persistence-drift/SKILL.md · 226 lines

How it starts

The opening of the file, as written. The whole thing — 226 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Persistence — Drift / SQLite

The on-device store is the single source of truth: with no server, everything must rebuild from this DB alone after process death, reboot, or restore. Push invariants into the schema, confine Drift to one layer, make every mutation one durable transaction, and store canonical values only. Applies to any lib/data/ Drift table, DAO, repository, connection setup, or backup.

Read the reference for the task at hand:

  • references/schema-and-daos.md — audit-column mixin, STRICT/CHECK/FK invariants, canonical column types, the index + EXPLAIN QUERY PLAN gate, DAO↔repository split, files-on-disk-with-relative-paths for blobs.
  • references/backup-and-wal.md — the checkpoint→vacuum→verify-by-reopen primitive, WAL rules, the backup-before-anything lesson, optional SQLCipher (key-first, assert-cipher, header-check).
  • references/persistence-without-drift.md — the same discipline for a small app on plain JSON files (injected base dir, debounce + lifecycle flush, atomic writes, lenient decode).

Run scripts/check-drift-confinement.sh and scripts/check-persistence-bans.sh before a PR. Migrations and their tests: see run-migration.

Non-negotiable rules

  1. Drift lives only in lib/data/; everything else sees value types. package:drift and package:sqlite3 are imported nowhere else — a banned-import lint/grep enforces it. DAOs map rows to immutable value objects; no Table, Companion, TableInfo, or generated row class crosses the boundary. A feature reaching for a raw query is a layering break that also blocks pure testing of everything above it.
  2. Put invariants in the schema, not at call sites. Tables are STRICT (no silent coercion); enumerable columns get CHECK (col IN (...)), ranges get CHECK (qty BETWEEN 0 AND n) / CHECK (amount_minor >= 0), relations are foreign keys with an explicit onDelete, uniqueness is a (partial) UNIQUE INDEX. A corrupt row must be unrepresentable at the storage layer, not merely policed in Dart.
  3. foreign_keys and synchronous are set in beforeOpen/setup on EVERY open; journal_mode = WAL is set idempotently there too. foreign_keys and synchronous are per-connection and are not persisted in the file, so they must be re-asserted on every open. journal_mode = WAL, by contrast, is persisted in the database file header and survives across connections — but it is still set idempotently in setup so a freshly created or restored DB adopts it. PRAGMA foreign_keys = ON unconditionally (SQLite defaults it OFF and silently no-ops FK actions when off); journal_mode = WAL for concurrent durable reads; synchronous = FULL on any store holding non-regenerable user data (WAL+NORMAL "might rollback following a power failure"). Seeding, and only seeding, goes inside if (details.wasCreated).
  4. One db.transaction per mutation; every query inside awaited; persist before publish. A mutation that writes several rows (parent + dependents, or a debit + a credit) is all-or-nothing. A missing await inside transaction(() async { lets a query run after the transaction closes — Drift calls this data loss; it is a release blocker. The DAO Future resolves only after the durable commit; the committed write then makes the watched .watch() stream re-emit the new state on its own — never an optimistic pre-commit update, never a manual state = … republish, never "save later". (The write→UI-update rule is owned by state-management-riverpod.)
  5. Store canonical values only; convert at the presentation edge. Money as integer minor units keyed to the real ISO-4217 exponent (never a REAL/double), other quantities as SI integers, true instants as UTC epoch millis. The local calendar day (anything that drives a day boundary) is a serial-day integer, never a DateTime instant — an instant reintroduces the DST/timezone off-by-one. No display strings, localized numerals, or formatted values in any column; switching locale/unit must leave stored rows byte-identical.
  6. Derived state is recomputed on read, never stored as a second authority. Counts, streaks, running totals, histograms are pure folds over their source rows, computed by one watch…/query fold next to the data. A stored copy is a second source of truth that drifts and that any future sync must reconcile twice.
  7. The repository is the single write path and the single source of truth. DAOs hold single-table queries; repositories own cross-table transactions and row→value-object mapping, and return a typed Result<T, Failure> for fallible work. Feature code depends on the repository abstraction, never on a DAO or Drift row.
  8. Reads are scoped .watch() streams; pagination is keyset, not OFFSET. Never subscribe to an unscoped app-wide stream (it recomputes on every write); scope by owner/entity + time window. History uses WHERE ts < :cursor ORDER BY ts DESC LIMIT n; OFFSET degrades badly on large tables.
  9. Blob bytes never live in SQLite. Store files on disk (app-private) with only a metadata row; persist the path relative to a base directory and resolve to absolute at read time — an absolute path dies on iOS reinstall/restore when the container UUID changes, and the row survives while the file renders blank with no error. BLOBs bloat the DB and slow every checkpoint and backup.
  10. Back up via wal_checkpoint(TRUNCATE) + VACUUM INTO, then verify by reopen — never File.copy a live WAL DB. A raw copy of a WAL-mode DB captures a torn state across the -wal/-shm sidecars and is corrupt and unrestorable. A backup that was not re-opened and integrity-checked did not succeed. Detail in references/backup-and-wal.md.
  11. Schema evolution is forward-only, append-only, and snapshot-guarded — and it is a separate ritual. Bump schemaVersion, add a new stepByStep step (never edit a shipped one), commit the schema snapshot, and ship no migration without a content-level test. That whole workflow lives in run-migration; this skill defines the tables it migrates.

Read the full file on GitHub · 226 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 7d ago First seen · 226 lines · 218 tokens per session scan A fbc122997aa7

Subscribe to this mod's changes

persistence-drift is a skill published in the GitHub repository zakariaf/Flutter-Skills (2 stars, last pushed 9d ago), licensed MIT. It adds 218 tokens to every session and 4,491 once invoked, about $0.0011 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.

Related

Other skills, from other repositories

android-persistence

Implement Room schemas and DataStore preferences with proper async patterns in Android. Use when the primary task is storage schema, DAO, migration, or preference isolation; defer auth-token/security storage, any CoroutineWorker/WorkManager task, Hilt graph wiring, and cache-policy design.

HoangNguyen0403/agent-skills-standard · 59 tokens

firebase-database

Use when syncing real-time data, structuring JSON trees, reading/writing, creating listeners, enabling offline persistence, managing presence, sharding, or writing security rules.

evanca/flutter-ai-rules · 38 tokens

common-store-changelog

Generate user-facing release notes for the App Store and Google Play from git history (App Store <=4000 chars, Google Play <=500). Use when generating release notes, app store changelog, play store release, or "what's new" text for a mobile app.

HoangNguyen0403/agent-skills-standard · 60 tokens

android-navigation-3

Install and migrate to Jetpack Navigation 3. Use when implementing Navigation 3 patterns including NavDisplay, NavKey routes, deep links, multiple backstacks, scenes (dialogs, bottom sheets), or migrating from Navigation 2.

HoangNguyen0403/agent-skills-standard · 52 tokens

flutter-auto-route-navigation

Implement typed routing, nested routes, and auth guards using autoroute in Flutter. Use when the task explicitly uses autoroute or its generated router; defer generic deep-link setup and other routing libraries.

HoangNguyen0403/agent-skills-standard · 44 tokens

flutter-dependency-injection

Configure service locator setup using injectable and getit in Flutter. Use when wiring dependency injection with getit or injectable.

HoangNguyen0403/agent-skills-standard · 29 tokens