mobile-offline-support · secondsky — Claude Code skill: offline-first mobile apps
A skill for offline-first mobile apps: local storage, a sync queue and conflict resolution, so the agent stops assuming the network is always there.
npx skills add secondsky/claude-skills --skill mobile-offline-support -a claude-codeWhat mobile-offline-support does
The skill hands the agent a working pattern for data that has to survive a dropped connection. At its core is an OfflineManager class for React Native: reads and writes go through AsyncStorage, and NetInfo reports whether the device is online.
When the connection is gone, changes land in a sync queue instead of being sent. The queue is capped by MAX_SYNC_QUEUE_LENGTH, set to 1000 — past that, the oldest entries get dropped with a console warning. Conflicts are settled by resolveConflict using last-write-wins, with a commented-out merge variant if you prefer that. An OfflineIndicator component renders a banner while the device is offline.
Both fetchFromServer and syncToServer carry TODO markers. They are examples, not a client. Point them at your own endpoints and API_BASE_URL before trusting a single request. Native paths for iOS Core Data and Android Room with WorkManager live in references/native-implementations.md.
What it helps with
- keep form data when the connection drops
- flush queued changes once the device is back online
- settle a conflict between local and server copies of a record
- tell the user the app is running offline
- cap how far the sync queue can grow
Example prompts for the agent
- Add offline support to the checkout screen with local storage and a sync queue
- Why do sync conflicts overwrite newer data? Walk through resolveConflict
- Add an offline banner using OfflineIndicator
How to install mobile-offline-support
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill mobile-offline-support -a claude-code2Manually: put the files in place
~/.claude/skills/mobile-offline-support/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/mobile-offline-support/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill mobile-offline-support -a codex2Manually: put the files in place
.agents/skills/mobile-offline-support/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill mobile-offline-support -a cursor2Manually: put the files in place
.cursor/skills/mobile-offline-support/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install secondsky/claude-skills mobile-offline-support2Manually: put the files in place
.github/skills/mobile-offline-support/SKILL.md1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill mobile-offline-support -a gemini-cli2Platform CLI
gemini skills install https://github.com/secondsky/claude-skills --path plugins/mobile-offline-support/skills/mobile-offline-supportManually: put the files in place
.devin/skills/mobile-offline-support/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill mobile-offline-support -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about mobile-offline-support
How do I install mobile-offline-support in Claude?
Run npx skills add secondsky/claude-skills --skill mobile-offline-support -a claude-code. The skill lands in ~/.claude/skills/mobile-offline-support/SKILL.md.
What does mobile-offline-support do?
It gives the agent patterns for offline-first mobile apps: caching in local storage, a deferred sync queue, conflict resolution and an offline indicator.
What breaks in mobile-offline-support?
fetchFromServer and syncToServer are stubs marked TODO. Without your own endpoints and API_BASE_URL, nothing syncs.
Source text
SKILL.md · MIT
---
name: mobile-offline-support
description: Offline-first mobile apps with local storage, sync queues, conflict resolution. Use for offline functionality, data sync, connectivity handling, or encountering sync conflicts, queue management, storage limits, network transition errors.
license: MIT
---
# Mobile Offline Support
Build offline-first mobile applications with local storage and synchronization.
## React Native Implementation
```javascript
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';
class OfflineManager {
constructor() {
this.syncQueue = [];
this.isOnline = true;
// Maximum items in sync queue before discarding oldest
this.MAX_SYNC_QUEUE_LENGTH = 1000;
NetInfo.addEventListener(state => {
this.isOnline = state.isConnected;
if (this.isOnline) this.processQueue();
});
}
/**
* Fetch data from server.
* TODO: Replace with actual API endpoint implementation.
*/
async fetchFromServer(key) {
try {
// Example implementation - replace with your API
const response = await fetch(`${API_BASE_URL}/data/${key}`);
if (!response.ok) {
throw new Error(`Server returned ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('fetchFromServer failed:', error);
throw new Error(`Failed to fetch ${key}: ${error.message}`);
}
}
/**
* Sync data to server.
* TODO: Replace with actual API endpoint implementation.
*/
async syncToServer(key, data) {
try {
// Example implementation - replace with your API
const response = await fetch(`${API_BASE_URL}/data/${key}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`Server returned ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('syncToServer failed:', error);
throw new Error(`Failed to sync ${key}: ${error.message}`);
}
}
async getData(key) {
const cached = await AsyncStorage.getItem(key);
if (cached) return JSON.parse(cached);
if (this.isOnline) {
const data = await this.fetchFromServer(key);
await AsyncStorage.setItem(key, JSON.stringify(data));
return data;
}
return null;
}
async saveData(key, data) {
await AsyncStorage.setItem(key, JSON.stringify(data));
if (this.isOnline) {
await this.syncToServer(key, data);
} else {
// Add to queue
this.syncQueue.push({ key, data, timestamp: Date.now() });
// Enforce queue bounds - discard oldest if exceeded
while (this.syncQueue.length > this.MAX_SYNC_QUEUE_LENGTH) {
const discarded = this.syncQueue.shift();
console.warn(`Sync queue full - discarded oldest item: ${discarded.key}`);
}
// Persist trimmed queue
await AsyncStorage.setItem('syncQueue', JSON.stringify(this.syncQueue));
}
}
async processQueue() {
const failedItems = [];
for (const item of this.syncQueue) {
try {
await this.syncToServer(item.key, item.data);
} catch (err) {
console.error('Sync failed:', err);
failedItems.push(item);
}
}
this.syncQueue = failedItems;
if (failedItems.length === 0) {
await AsyncStorage.removeItem('syncQueue');
} else {
await AsyncStorage.setItem('syncQueue', JSON.stringify(failedItems));
}
}
}
```
## Conflict Resolution
```javascript
function resolveConflict(local, server) {
// Last-write-wins
if (local.updatedAt > server.updatedAt) return local;
return server;
// Or merge changes
// return { ...server, ...local };
}
```
## UI Indicators
```jsx
function OfflineIndicator() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
return NetInfo.addEventListener(state => {
setIsOnline(state.isConnected);
});
}, []);
if (isOnline) return null;
return (
<View style={styles.banner}>
<Text>You're offline. Changes will sync when connected.</Text>
</View>
);
}
```
## Best Practices
- Cache frequently accessed data locally
- Queue actions for later sync
- Show clear offline indicators
- Handle sync conflicts gracefully
- Compress stored data
- Test offline scenarios thoroughly
## Native Implementations
See [references/native-implementations.md](references/native-implementations.md) for:
- iOS Core Data with sync manager
- Android Room database with WorkManager sync
## Avoid
- Assuming connectivity
- Losing data on sync failures
- Unbounded queue growth
- Syncing sensitive data insecurely
© secondsky · MIT · secondsky/claude-skills
Similar skills
Everything for Mobile →mobile-offline-support by other authors comes first.