The Edge Memory Protocol (EMP) is an open standard for sharing AI memory across multiple applications on mobile devices. It enables local-first, privacy-preserving memory storage that any app can read from and write to with user consent.
- Local-First: All data remains on the device
- Privacy-Preserving: User controls access and can view/edit/delete all data
- Interoperable: Simple format that any app or LLM can parse
- Cross-App: Multiple apps from different developers can share memory
- Platform-Native: Uses OS-provided storage mechanisms
- Minimal Footprint: Works on resource-constrained devices
Each memory entry is a single line of JSON, making the format:
- Append-friendly: New entries are simply appended
- Human-readable: Can be inspected with any text editor
- Parseable: Standard JSON parsing, no special libraries needed
- Resilient: Corruption affects only individual lines, not entire file
Standard Paths:
- iOS:
On My iPhone/EdgeMemory/memory.jsonloriCloud Drive/EdgeMemory/memory.jsonl - Android:
/storage/emulated/0/Documents/EdgeMemory/memory.jsonl
Apps access these locations through platform-specific APIs (Files app on iOS, Storage Access Framework on Android).
interface EdgeMemoryEntry {
v: string; // Protocol version (e.g., "1.0")
id: string; // Unique identifier (UUID v4)
ts: number; // Unix timestamp in milliseconds
src: string; // Source app (reverse domain notation)
content: string; // The memory content
type?: string; // Memory type (optional)
tags?: string[]; // Tags for filtering (optional)
meta?: Record<string, any>; // App-specific metadata (optional)
emb?: number[]; // Embedding vector (optional)
}-
v(string): Protocol version number- Format:
"MAJOR.MINOR"(e.g.,"1.0") - Used for backward compatibility
- Format:
-
id(string): Unique identifier- Must be a valid UUID v4
- Used for deduplication and updates
-
ts(number): Timestamp- Unix timestamp in milliseconds
- Used for ordering and filtering by time
-
src(string): Source application- Reverse domain notation (e.g.,
"com.company.appname") - Identifies which app created the entry
- Reverse domain notation (e.g.,
-
content(string): Memory content- The actual memory text
- UTF-8 encoded
- No length limit (but keep reasonable for mobile)
-
type(string): Memory type- Suggested values:
"preference","fact","event","conversation","note" - Apps can define custom types
- Suggested values:
-
tags(string[]): Tags for categorization- Array of lowercase strings
- Used for filtering and search
- Examples:
["ui", "theme"],["person:john", "calendar"]
-
meta(object): App-specific metadata- Arbitrary JSON object
- Other apps should ignore unknown metadata
- Examples:
{"priority": "high"},{"location": "home"}
-
emb(number[]): Embedding vector- Array of floats representing semantic embedding
- Used for vector similarity search
- Dimension should be documented by the app
{"v":"1.0","id":"550e8400-e29b-41d4-a716-446655440000","ts":1701234567890,"src":"com.example.chat","content":"User prefers dark mode","type":"preference","tags":["ui","theme"]}
{"v":"1.0","id":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","ts":1701234568000,"src":"com.example.notes","content":"Meeting with John on Friday at 2pm","type":"event","tags":["calendar","person:john"],"meta":{"priority":"high"}}
{"v":"1.0","id":"6ba7b811-9dad-11d1-80b4-00c04fd430c8","ts":1701234569000,"src":"com.example.assistant","content":"User asked about weather in San Francisco","type":"conversation","emb":[0.123,0.456,0.789]}- Read All: Load entire file and parse each line
- Filter by Time: Read entries where
ts >= startTime && ts <= endTime - Filter by Tags: Read entries where
tagsincludes specified tag(s) - Filter by Type: Read entries where
typematches specified type - Search by Content: Read entries where
contentcontains keyword (case-insensitive) - Semantic Search: Read entries with similar
embvectors (if embeddings present)
- Append: Add new entry to end of file
- Update: Append new entry with same
id(newertstakes precedence) - Delete: Append tombstone entry or rewrite file without deleted entry
File Locking: Apps must implement file locking to prevent concurrent writes from corrupting the file.
Recommended approach:
- Create lock file (
memory.jsonl.lock) before writing - Write to file
- Remove lock file
- If lock file exists, wait with exponential backoff
Alternative: Use platform-specific atomic write operations
Access Method: Files app with security-scoped bookmarks
- App requests user to select EdgeMemory folder via
UIDocumentPickerViewController - User navigates to or creates
EdgeMemoryfolder in Files app - App saves security-scoped bookmark for persistent access
- Future launches use bookmark to access folder
Required Capabilities:
UISupportsDocumentBrowserin Info.plist- Document picker entitlements
Code Example:
// Request access to folder
let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder])
picker.delegate = self
present(picker, animated: true)
// Save bookmark
let bookmark = try url.bookmarkData(options: .minimalBookmark)
UserDefaults.standard.set(bookmark, forKey: "edgeMemoryBookmark")
// Restore access
var isStale = false
let url = try URL(resolvingBookmarkData: bookmark, bookmarkDataIsStale: &isStale)
let accessed = url.startAccessingSecurityScopedResource()
defer { url.stopAccessingSecurityScopedResource() }Access Method: Storage Access Framework or standard Documents folder
Option 1: Standard Location (Android 10+)
val documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val edgeMemoryDir = File(documentsDir, "EdgeMemory")
val memoryFile = File(edgeMemoryDir, "memory.jsonl")Option 2: Storage Access Framework
// Request user to pick folder
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(intent, REQUEST_CODE)
// Save URI for persistent access
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)Required Permissions:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>- Explicit Consent: User must explicitly grant each app access to the memory folder
- Transparency: Users can view the memory file with any text editor
- Revocable: Users can revoke access at any time through OS settings
- Deletable: Users can delete individual entries or entire file
- Local-Only: Data never leaves the device (unless user uses cloud storage like iCloud)
- App Isolation: Apps can only access memory if user grants permission
- Optional Encryption: Apps can encrypt the
contentfield using device keychain - Audit Trail: Each entry includes
srcfield showing which app created it
Apps may encrypt the content field:
{"v":"1.0","id":"...","ts":123,"src":"com.app","content":"encrypted:AES256:base64encodeddata"}Encryption scheme:
- Prefix:
encrypted:ALGORITHM: - Key storage: OS keychain/keystore
- Shared key: Apps can share encryption key through secure channel if needed
Current version: 1.0
Version format: MAJOR.MINOR
- MAJOR: Breaking changes (incompatible format)
- MINOR: Backward-compatible additions
Apps must handle entries with different protocol versions:
- Parse
vfield first - Support older versions when possible
- Ignore unknown fields in newer versions
Proposed features for future versions:
- Compression (gzip)
- Archival (split by time period)
- Conflict resolution strategies
- Real-time sync protocol
- Differential updates
- Validate entries: Check schema before writing
- Use meaningful tags: Help other apps filter relevant memories
- Respect privacy: Don't write sensitive data without user consent
- Handle errors gracefully: File may be locked or inaccessible
- Implement backoff: Wait before retrying failed operations
- Document metadata: If using custom
metafields, document them - Test cross-app: Verify your app works with other EMP-compatible apps
- Review regularly: Check what memories are being stored
- Delete old entries: Keep file size manageable
- Backup: Copy file to safe location periodically
- Control access: Only grant permission to trusted apps
See @edge-memory/core for a reference TypeScript/React Native implementation.
This specification is released under CC0 1.0 Universal (Public Domain).
Proposals for future versions should be submitted as issues or pull requests to the Edge Memory Protocol repository.
- Initial specification
- JSONL format
- Core schema definition
- Platform-specific access patterns