Skip to content
Agentmart
Submit a tool

data-export-and-restore

Builds data export and restore - a versioned, checksummed backup file, all-or-nothing restore, safe CSV.

Skill by zakariaf

IndexedMIT★ 11
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/zakariaf-data-export-and-restore

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Builds data export and restore - a versioned, checksummed backup file, all-or-nothing restore, safe CSV. Use when adding backup, restore, import, export or CSV files. Not for the database (persistence-and-migrations).

Use cases: spreadsheets, backend, data

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/data-export-and-restore

What's inside

Skill name
data-export-and-restore
Description
Builds data export and restore - a versioned, checksummed backup file, all-or-nothing restore, safe CSV. Use when adding backup, restore, import, export or CSV files. Not for the database (persistence-and-migrations).
License
MIT
Instructions
212 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (87)

  • SKILL.md
  • shared.json · assets/
  • template-placeholders.json · assets/
  • backup-schema.ts · examples/backup-v2/src/data/backup/
  • backup-upgrades.ts · examples/backup-v2/src/data/backup/
  • backup-v2.json · examples/backup-v2/src/data/backup/fixtures/
  • sqlite-backup-repository.ts · examples/backup-v2/src/data/backup/
  • v0002-add-task-due-on.ts · examples/backup-v2/src/data/backup/upgrades/
  • migrations.ts · examples/backup-v2/src/data/migrations/
  • v0002-add-task-due-date.ts · examples/backup-v2/src/data/migrations/
  • backup-round-trip.test.ts · examples/backup-v2/test/sqlite/
  • architecture.json · examples/contracts/
  • backup-failure-messages.ts · examples/src/features/backup/
  • backup-screen.tsx · examples/src/features/backup/
  • backup-action.tsx · examples/src/features/backup/components/
  • restore-confirmation.tsx · examples/src/features/backup/components/
  • use-backup-model.ts · examples/src/features/backup/
  • csv-and-formats.md · references/
  • envelope-and-ladder.md · references/
  • platform-behaviour.md · references/
  • restore-policy.md · references/
  • testing-and-checker.md · references/
  • check-backup.mjs · scripts/
  • check-lib.mjs · scripts/
  • inspect-backup.mjs · scripts/
  • backup-envelope.mjs · scripts/lib/
  • backup-rules.mjs · scripts/lib/
  • repo-rules.mjs · scripts/lib/
  • source-scan.mjs · scripts/lib/
  • selftest.mjs · scripts/
  • canonical-json.test.ts · templates/src/core/portable/
  • canonical-json.ts · templates/src/core/portable/
  • csv.test.ts · templates/src/core/portable/
  • csv.ts · templates/src/core/portable/
  • sha256.test.ts · templates/src/core/portable/
  • sha256.ts · templates/src/core/portable/
  • utf8.ts · templates/src/core/portable/
  • result.test.ts · templates/src/core/
  • result.ts · templates/src/core/
  • backup-envelope.test.ts · templates/src/data/backup/
  • backup-envelope.ts · templates/src/data/backup/
  • backup-failures.ts · templates/src/data/backup/
  • backup-repository.ts · templates/src/data/backup/
  • backup-schema.ts · templates/src/data/backup/
  • backup-service.test.ts · templates/src/data/backup/
  • backup-service.ts · templates/src/data/backup/
  • backup-upgrade-step.ts · templates/src/data/backup/
  • backup-upgrades.test.ts · templates/src/data/backup/
  • backup-upgrades.ts · templates/src/data/backup/
  • fake-backup-repository.test.ts · templates/src/data/backup/
  • fake-backup-repository.ts · templates/src/data/backup/
  • backup-v1.json · templates/src/data/backup/fixtures/
  • read-backup.test.ts · templates/src/data/backup/
  • read-backup.ts · templates/src/data/backup/
  • sqlite-backup-repository.ts · templates/src/data/backup/
  • tasks-csv.test.ts · templates/src/data/backup/
  • tasks-csv.ts · templates/src/data/backup/
  • migration-runner.ts · templates/src/data/migrations/
  • sql-driver.ts · templates/src/data/
  • expo-file-system-export-files-adapter.ts · templates/src/services/export-files/
  • …and 27 more

SKILL.md (first lines)

# Data export and restore

A backup is a versioned, checksummed file of the user's tables that this app (and only a backup) can
restore; a restore checks the whole file first, keeps a safety copy, then replaces every table in one
transaction or changes nothing; a CSV export is guarded against broken rows and formula injection; files
leave or enter the app only through ports, from a press; tests prove the round trip byte for byte.

## Rules that must hold

1. **Backup and export are different features; restore accepts only the backup envelope.** A CSV or a
   report is lossy and never restorable (it fails as `not-a-backup`). Why: the moment a CSV restores, a
   format built for reading becomes someone's only copy, with no versions, types or checksum.
2. **Every backup is the envelope: `format`, `formatVersion`, `schemaVersion`, `appVersion`,
   `exportedAt` (UTC), `payloadSha256`, in that order, then the canonical payload last;
   `BACKUP_SCHEMA_VERSION = LATEST_DB_VERSION`.** Why: an unversioned file can only be misread, never
   refused, and header first lets a truncated file of ours be called damaged. (`envelope-header`,
   `schema-version`)
3. **A picked file climbs the whole ladder before anything is written**: size (the one
   `MAX_BACKUP_BYTES`, which export also refuses to exceed), readable, ours, strict
   header, checksum before any row, not newer than the build, every row through its schema (text bounds
   in code points, as SQLite counts), ids unique and parents present. The name and MIME type are never
   trusted. Why: a broken file must fail with its own reason, not half-way through the rows.
   (`checksum-first`, `newer-refused`)
4. **Restore is replace, all or nothing**: the user confirms a preview that names the policy and the
   counts (and the unreadable current rows the replace also removes); the current data is written to a
   private safety copy first (no copy, or one over the size limit, no restore); then one
   transaction deletes and inserts every backed-up table, ids kept; a preview restores once; never into
   a session running in memory. The app offers the copy back (`previewSafetyCopy`), because no picker
   can reach the private folder. Why: a half-restored database is worse than a failed restore, and the
   copy is the undo for restoring the wrong file. (`restore-transaction`, `safety-copy-first`)
5. **A backup covers every user table and never a protected one**: each table the migrations create is
   in `BACKUP_PAYLOAD` or in `BACKUP_EXCLUDED_TABLES` with its reason; entitlements, diagnostics and
   secrets are never backed up or restored. Why: a forgotten table is data lost on the next restore, and
   a restorable entitlement is a free purchase for anyone who edits the file. (`backup-coverage`,
   `restore-protected`)
6. **Older backups upgrade through frozen, pure JSON steps, one per migration, proven equal to the
   migrations by the parity test; every schema version has a frozen backup fixture.** Why: users hold
   files from every version, and two upgrade paths drift apart unless a test pins them together.
   (`upgrade-chain`, `backup-fixture`)
7. **The round-trip test passes on hostile data**: export, restore into an empty database, export again
   gives the same bytes; restoring twice gives the same rows; every refusal leaves the data unchanged.
   Why: `'test1'` survives everything and proves nothing. (`round-trip-test`)
8. **Machine formats hold canonical values only**: integers, `.` decimals, ISO-8601 UTC or epoch ms,
   date keys, codes, untranslated column names; localization happens on screen. Why: `12,5`, `١٢٫٥` and
   `12.5` are one number and three parses. (`canonical-values`)
9. **Every CSV goes through the one guarded encoder**: a text cell starting with `= + - @`, tab or CR
   gets an apostrophe, then RFC 4180 quoting (quotes doubled, spaces and newlines kept), CRLF, UTF-8 with
   a BOM for spreadsheets. Why: a hand-joined cell breaks on a comma and runs as a formula in the
   recipient's spreadsheet. (`csv-guard`, `csv-hand-rolled`)
10. **Files are published atomically**: a temp file in the same folder, moved over the published name,
    deleted on failure; free space checked first; shared exports live in the cache and are swept on the
    next export, never deleted when the share sheet closes. Why: a truncated file with a trusted name is
    the failure that surfaces months later. (`atomic-write`)
11. **The share sheet, the picker and the file system sit behind ports, and run only from a user's
    press**; these ports never upload. Why: Jest never touches native code, and a file leaves through
    them only when the user asks. An opt-in scheduled cloud backup is a separate feature with the same
    envelope and ladder. (`sdk-behind-port`, `user-action-only`)
12. **Export, pick and restore return typed Results with one failure kind per reason; backup code never
    throws.** Why: "Restore failed" alone cannot be told apart from data loss. (`typed-failures`)

## Workflow

1. Read [references/envelope-and-ladder.md](references/envelope-and-ladder.md) (the file, the checksum,
   the ladder, upgrades, fixtures) and [references/restore-policy.md](references/restore-policy.md)
   (replace, the transaction, the safety copy, the confirmation, excluded tables).
2. Prerequisites: the app database from persistence-and-migrations (`SqlDriver`, migrations,
   `contracts/persistence.json`, `AppData`) and the Result module from error-handling-typed-results. Then
   `npx expo install expo-file-system expo-sharing expo-document-picker` (SDK 57: `~57.0.7`,
   `~57.0.22`, `~57.0.3`; verified 2026-10-10; re-verify with `npx expo install --check`).
3. Stop and ask the developer to classify the two new SDKs (an architecture decision): merge
   `examples/contracts/architecture.json` into the app's `contracts/architecture.json` and add both to
   `VENDOR_SDK_PATHS` in `eslint.config.mjs` in the same commit
   ([references/platform-behaviour.md](references/platform-behaviour.md), section 7).
4. Copy the templates: `templates/src/core/portable/`, `templates/src/data/backup/` (with
   `fixtures/backup-v1.json`), `templates/src/services/{export-files,share-sheet,file-picker}/`,
   `templates/test/portable/`, `templates/test/sqlite/{sqlite-backup-repository,backup-round-trip}.test.ts`
   (skip the synced files the app already has from their owners). Replace `__APP_SLUG__` (the format
   marker and file names). Replace the Tasks tables with the app's own in `backup-schema.ts`, the SQLite
   backup repository (literal SELECT/DELETE/INSERT per table, children of a skipped parent left out in
   `readAll`), `consistencyFailure`, `tasks-csv.ts`, the frozen fixture and the tests; list every other
   table in `BACKUP_EXCLUDED_TABLES` with its reason. Set `FIRST_BACKUP_SCHEMA_VERSION` in
   `backup-envelope.ts` to the app's current `LATEST_DB_VERSION` (the template's `1` fits only an app
   whose database is still at version 1); it never changes after the first release with backups. No
   upgrade steps or fixtures exist for versions before it: never invent them to satisfy the checker.
5. Make the frozen fixture for the current schema (N = `FIRST_BACKUP_SCHEMA_VERSION`): export with the
   app over hostile rows (quotes, `=1+2`, CRLF, RTL with marks, emoji at the maximum length, blanks, a
   gap in ids) and commit it as `src/data/backup/fixtures/backup-v<N>.json` with its FIXTURES entry,
   replacing the template's `backup-v1.json` when N > 1. Never edit it afterwards.
6. Compose once: the three adapters in `createDeviceServices` (fakes in `createTestServices`), and
   `backup: createBackupService({ ..., isPersistent: database.isPersistent })` in the data layer's device
   opener as a member of `AppData` (platform-behaviour.md, section 7).
7. Build the screen from `examples/src/features/backup/` (model, pure view, one message per failure
   kind): one action at a time with the busy state painted first, an iPad anchor per share button, the
   confirmation naming "replace", both counts and the date formatted on screen, the "Restore the data
   from before your last restore" row, `skippedRows` and `currentSkippedRows` shown, a failed phase
   when a job throws (never stuck on working), and the restore run through the store
   layer's `updateAndPublish` so every store re-reads. CSV and reports:
   [references/csv-and-formats.md](references/csv-and-formats.md).
8. A table changes later: follow "Adding schema version N+1" in envelope-and-ladder.md, imitating
   `examples/backup-v2/`, in the same change as the migration.
9. Run the tests ([references/testing-and-checker.md](references/testing-and-checker.md)):
   `npx jest src/core/portable src/data/backup src/services/export-files src/services/share-sheet src/services/file-picker test/sqlite --ci`
   and `npm run typecheck`.
10. After an adapter change, run the export-share-restore drill on a named iOS simulator and Android
    emulator (platform-behaviour.md, section 8), or say in the report that it is owed.
11. Run `node ${CLAUDE_SKILL_DIR}/scripts/check-backup.mjs .`; fix every `FAIL` line and rerun until it
    prints `RESULT: PASS`. For a user's file: `node ${CLAUDE_SKILL_DIR}/scripts/inspect-backup.mjs <file> --format <slug>.backup --schema <N>`.

## Definition of done

- [ ] Backup and CSV are separate actions; the envelope's header comes first in the order of rule 2, the
      payload is canonical JSON and `payloadSha256` its SHA-256; `BACKUP_SCHEMA_VERSION = LATEST_DB_VERSION`.
- [ ] `readBackup` runs the whole ladder with one failure kind per reason, the checksum before any row,
      newer files refused; the picked file's size is checked before it is read, and export refuses a
      backup above the same `MAX_BACKUP_BYTES` or one that fails rung 7.
- [ ] Restore shows a preview naming "replace" and the counts, writes the safety copy first, replaces in
      one transaction (ids kept), restores a preview once, refuses a session in memory; stores re-read
      afterwards; the screen offers the safety copy back through `previewSafetyCopy`.
- [ ] Every migrated table is backed up or excluded with its reason; no protected table, secret or

From zakariaf/ReactNative-Skills, MIT.

More from zakariaf/ReactNative-Skills

Signals

Stars
11
Forks
2
Open issues
0
Last commit (this folder)
Oct 17, 2026 (11 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from zakariaf

Cite this page

data-export-and-restore skill. Agent Mart. https://agentmart.dev/skills/zakariaf-data-export-and-restore (last updated 2026-10-24)