install
source · Clone the upstream repo
git clone https://github.com/a5c-ai/babysitter
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/mobile-development/skills/offline-storage" ~/.claude/skills/a5c-ai-babysitter-mobile-offline-storage && rm -rf "$T"
manifest:
library/specializations/mobile-development/skills/offline-storage/SKILL.mdsource content
Mobile Offline Storage Skill
Overview
This skill provides cross-platform offline-first data management capabilities. It enables configuration of WatermelonDB, Realm, MMKV, and other offline storage solutions with sync queue architectures.
Allowed Tools
- Execute package managers and build toolsbash
- Analyze storage configurations and schemasread
- Generate models and sync logicwrite
- Update storage implementationsedit
- Search for storage filesglob
- Search for patternsgrep
Capabilities
WatermelonDB (React Native)
-
Schema Definition
- Define table schemas
- Configure column types
- Set up relations
- Handle migrations
-
Sync Engine
- Implement sync adapters
- Handle conflict resolution
- Configure batch operations
- Manage sync state
Realm (Cross-Platform)
-
Object Schemas
- Define Realm objects
- Configure primary keys
- Set up relationships
- Handle embedded objects
-
Realm Sync
- Configure Device Sync
- Handle flexible sync
- Manage subscriptions
- Handle conflicts
MMKV
- Key-Value Storage
- Configure MMKV instances
- Handle encryption
- Implement migrations
- Manage namespaces
Sync Architecture
-
Offline-First Patterns
- Design sync queues
- Handle network state
- Implement retry logic
- Manage pending operations
-
Conflict Resolution
- Last-write-wins strategy
- Merge strategies
- User resolution UI
- Audit logging
Target Processes
- Offline patternsoffline-first-architecture.js
- API syncrest-api-integration.js
- GraphQL syncgraphql-apollo-integration.js
Dependencies
- WatermelonDB (React Native)
- Realm SDK
- MMKV
- SQLite
Usage Examples
WatermelonDB Schema
// database/schema.ts import { appSchema, tableSchema } from '@nozbe/watermelondb'; export const schema = appSchema({ version: 1, tables: [ tableSchema({ name: 'posts', columns: [ { name: 'title', type: 'string' }, { name: 'body', type: 'string' }, { name: 'is_published', type: 'boolean' }, { name: 'author_id', type: 'string', isIndexed: true }, { name: 'created_at', type: 'number' }, { name: 'updated_at', type: 'number' }, ], }), tableSchema({ name: 'comments', columns: [ { name: 'body', type: 'string' }, { name: 'post_id', type: 'string', isIndexed: true }, { name: 'author_id', type: 'string' }, { name: 'created_at', type: 'number' }, ], }), ], });
WatermelonDB Model
// database/models/Post.ts import { Model, Q } from '@nozbe/watermelondb'; import { field, date, children, relation } from '@nozbe/watermelondb/decorators'; export class Post extends Model { static table = 'posts'; static associations = { comments: { type: 'has_many', foreignKey: 'post_id' }, author: { type: 'belongs_to', key: 'author_id' }, }; @field('title') title!: string; @field('body') body!: string; @field('is_published') isPublished!: boolean; @field('author_id') authorId!: string; @date('created_at') createdAt!: Date; @date('updated_at') updatedAt!: Date; @children('comments') comments!: Query<Comment>; @relation('users', 'author_id') author!: Relation<User>; }
Sync Queue Implementation
// sync/SyncQueue.ts interface SyncOperation { id: string; type: 'create' | 'update' | 'delete'; entity: string; payload: any; timestamp: number; retryCount: number; } class SyncQueue { private queue: SyncOperation[] = []; private isProcessing = false; async enqueue(operation: Omit<SyncOperation, 'id' | 'timestamp' | 'retryCount'>) { const op: SyncOperation = { ...operation, id: uuid(), timestamp: Date.now(), retryCount: 0, }; this.queue.push(op); await this.persistQueue(); this.processQueue(); } private async processQueue() { if (this.isProcessing || this.queue.length === 0) return; const isOnline = await NetInfo.fetch().then(state => state.isConnected); if (!isOnline) return; this.isProcessing = true; while (this.queue.length > 0) { const operation = this.queue[0]; try { await this.executeOperation(operation); this.queue.shift(); await this.persistQueue(); } catch (error) { operation.retryCount++; if (operation.retryCount >= 3) { this.queue.shift(); await this.logFailedOperation(operation, error); } break; } } this.isProcessing = false; } private async executeOperation(operation: SyncOperation) { switch (operation.type) { case 'create': return api.post(`/${operation.entity}`, operation.payload); case 'update': return api.put(`/${operation.entity}/${operation.payload.id}`, operation.payload); case 'delete': return api.delete(`/${operation.entity}/${operation.payload.id}`); } } }
Quality Gates
- Data integrity verified on sync
- Conflict resolution tested
- Offline functionality verified
- Migration tests passing
Related Skills
- iOS Core Dataios-persistence
- Android Roomandroid-room
- GraphQL offlinegraphql-mobile
Version History
- 1.0.0 - Initial release