offline-first-sync
Skill0 starsChanged 52 days agoMITView on GitHub
Build or debug an app that has to keep working with no network — local writes, a queue, and reconciliation on reconnect. Use when adding offline support, when work is lost on a dropped connection, when sync produces duplicates or silently drops records, or when photos and other large files need to survive being captured out of coverage.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- jasoncrawford/claude-skillstheir own version, first seen Apr 25, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- jasoncrawford/claude-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository17 other files it gives its agents.
- access-control-proofSkill
- agent-instructionsSkill
- contract-changeSkill
- data-change-scriptSkill
- deploy-safetySkill
- design-critiqueSkill
- evidence-layersSkill
- interface-craftSkill
- issue-ledgerSkill
- mobile-field-readinessSkill
- parallel-worktreesSkill
- requirements-elicitationSkill
- root-cause-investigationSkill
- solution-architectureSkill
- ux-state-coverageSkill
- versioned-publishingSkill
- skill-nameSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Every user action commits to local storage before anything is attempted over the network.
- Distinctive: line 44
If you do need multiple writers, choose the model explicitly and up front: last-write-wins per field with timestamps, an append-only log of …
- Distinctive: line 77
Never let the server allocate ids for offline-created records.
- Very specific: line 113
Keep the device time as captured_at — it is genuinely useful, it is what the user experienced — but order, expire and reconcile on a …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Offline-first sync
Offline support is not a feature bolted onto a networked app. It is a different ownership model: the device owns the work until the server acknowledges it. Retrofitting is expensive, so decide early.
1. Write locally first, always
Every user action commits to local storage before anything is attempted over the network. The network call is a consequence of the local write, never a precondition for it.
user taps -> local store (durable) -> UI updates -> queue entry -> sync attemptNot:
user taps -> POST -> wait -> on success, update UI <- fails in a liftThe test for whether you got this right: turn the radio off mid-session, force quit the app, reopen it. Everything the user did should still be there. Not "most of it" — a field worker who loses one form stops trusting the app and starts keeping paper.
2. Name the writer, and prefer one
Most conflict misery comes from not having decided who owns a record while it is in flight. The cheap, robust answer for form-and-checklist style apps is single writer: the device that started the draft owns it until submission, and the server does not modify it.
That is a real constraint, not a deficiency — but write it down, because the first feature request that breaks it (a reviewer editing someone's in-progress form from the web) needs a conflict model you do not currently have.
If you do need multiple writers, choose the model explicitly and up front: last-write-wins per field with timestamps, an append-only log of operations, or CRDTs. Each has a different data shape. You cannot retrofit one onto a design that assumed a different one.
3. Binary files need their own queue
Photos, audio, signatures and attachments behave differently from JSON records and should not share a queue with them:
- They are large, so they need progress, resumability and a size cap.
- They usually upload to a different place (object storage, a presigned URL) than the record does.
- They fail differently: the record can succeed while the photo is still uploading, which means the record has to reference a file that does not exist yet and the reader has to tolerate that.
- They fill the device. Cap the local cache, downscale on capture, and evict once uploaded and confirmed.
Store the local file reference in the record, swap it for the remote reference when the upload is acknowledged, and make the UI show the local copy until then so the user sees their own photo immediately.
4. Every queued operation carries an idempotency key
Generate the id on the device, at the moment of creation, and use it as the idempotency key for the whole lifetime of the record.
This one decision removes a whole category of bug. The retry after a timeout whose response was actually a success, the double-tap, the resumed upload — all of them collapse into the same request, and the server's job is just "create or return the existing one".
Never let the server allocate ids for offline-created records. A device-side temporary id that gets swapped for a server id means every local reference has to be rewritten, and the rewrite runs while new records are still being created.
5. "Synced" means acknowledged
Three states, not two:
| State | Meaning | Shown as |
local | Written on device, not sent | "Saved on this device" |
pending | Sent, no acknowledgement yet | "Sending..." |
synced | Server confirmed and durable | "Saved" |
A request that has been sent is not saved. Do not delete the local copy, mark
the record green, or let the user leave a screen believing the work is safe
until the server has said so. If the acknowledgement never comes, the record
goes back to local and retries — it does not vanish.
6. Reconnect is a stampede
The moment coverage returns, every queued item on every device tries at once, often on a weak edge connection that dropped for a reason.
- Send serially per device, or with a small concurrency cap. Not all at once.
- Exponential backoff with jitter. Without jitter, every device on the site retries on the same tick.
- Cap the retry count, then surface the failure to the user rather than retrying forever in silence.
- Make sync resumable: it will be interrupted halfway through, routinely.
7. Trust the server's clock for ordering
Device clocks are wrong. They are wrong by minutes on cheap hardware, by hours after a timezone change, and by whatever the user set them to.
Keep the device time as captured_at — it is genuinely useful, it is what the
user experienced — but order, expire and reconcile on a server-assigned
timestamp. Anything security-relevant (token expiry, a window in which an action
is allowed, an audit trail) uses server time only.
8. Show the state, in the user's words
- A persistent, quiet indicator for offline. Not a toast that disappears before it is read.
- A count of what is waiting, and a way to see the list.
- A manual "sync now", because someone will need it and its absence reads as the app being stuck.
- Plain language for failure: what failed, whether the work is safe, and what to do. "Sync error" tells a person on a site with no signal nothing at all.
9. Testing it
Unit tests will not find these bugs. The ones that do:
- Airplane mode on for the whole flow, then on again.
- Toggle mid-submit, at the exact moment the request is in flight.
- Force quit with a full queue; reopen.
- Throttle to slow 2G rather than cutting the connection cleanly — half-open connections and timeouts behave differently from a clean offline, and are more common in the field.
- Fill the storage quota and keep going.
- Two devices, the same record, if you allow that at all.
Checklist
- Local write happens before the network call, durably
- Writer model chosen and written down
- Binary uploads in their own resumable, capped queue
- Device-generated ids used as idempotency keys end to end
- Three sync states; local copy kept until acknowledged
- Serial or capped sync with backoff and jitter
- Server time for ordering and expiry; device time kept as capture time
- Offline state and pending count visible; manual sync available
- Tested with airplane mode, force quit, throttling and a full quota
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

