Building LMKFR

Why local-first matters for your Instagram export

Your Instagram data export is sensitive. A local-first approach means it never leaves your device unless you explicitly opt in. LMKFR processes everything client-side by default, with an opt-in claim layer designed to avoid taking your archive.

By default, your archive stays on your device. LMKFR runs entirely client-side in local mode. The optional claim layer is off unless both DATABASE_URL and CLAIM_SECRET are explicitly configured - it is opt-in, not on by default.

Local mode by default

Processing happens in your browser. The ZIP is read locally, parsed in a Web Worker, and the AMA index uses IndexedDB. No files are uploaded in local mode. When the claim layer is not configured, the app runs 100% offline/local.

Claim layer is opt-in

The claim layer (accounts/sessions/profiles) is enabled only when both DATABASE_URL and CLAIM_SECRET are set in the environment. If either is unset, claims are disabled with a friendly notice. Drizzle schema lives in db/schema.ts (users, sessions, profiles).

Practical protections

  • Parsing is isolated (Web Worker) to keep UI responsive and to contain processing.
  • CSP reports are console-only, bounded, deduped and discarded.
  • No multipart/ZIP upload endpoints accept archives for processing in the claim-free paths; the web app reads files locally.
  • Media never leaves the device in local mode. Public profile views are only the owner's own derived snapshot.
  • The codebase has no AI/LLM, no third-party trackers by default, and local mode is the default posture.

What this means for custody

You keep custody. Verification is straightforward: run in local mode with network disabled and observe that no outbound requests contain archive contents. The product posture is "read locally first, sync only if you explicitly choose to".

Does this upload my ZIP to a server?

No, in local mode nothing is uploaded. The app reads the ZIP file from your device. The claim layer is opt-in only.

Is local-first really the default?

Yes. Local mode is the default posture. The claim layer requires explicit environment configuration.

Can I verify it works offline?

Yes. Open the app, disable network, load your archive. Processing should complete without network requests for the archive contents.

What about the sync tier mentioned in docs?

Profile sync is an opt-in, split-key design described in the docs. It is not enabled by default and does not change the local-first default posture.

Sources of truth

  • SECURITY.md and product posture in AGENTS.md (local mode default, claim layer opt-in; no AI/LLM, no cross-user features, no third-party trackers by default).
  • Claim layer gating: enabled only when both DATABASE_URL and CLAIM_SECRET are set (local .env, gitignored). Unset -> 100% offline/local.
  • Route audit: no API route accepts multipart/ZIP for archive processing in claim-free paths (see P3 verification).
Why local-first matters for your Instagram export — LMKFR Blog