data-persistence

data-persistence is a skill for Claude Code, Codex from wangjianqi/AppStore. It costs 40 tokens per session (3,077 once invoked), scanned A, original, MIT.

A set of Swift guidelines for storing app data, including preferences, credentials, files, caches, and structured records.

In plain words
What is it for?
Use it when working with UserDefaults, Keychain, Core Data, SwiftData, FileManager, database migrations, caching, or sandboxed files.
Why use it?
It helps developers choose an appropriate storage method and avoid unsafe choices, such as saving passwords in ordinary app preferences.

Skill for Claude CodeCodex

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add skills/wangjianqi/appstore/11-data-persistence
Any agent
npx skills add wangjianqi/AppStore --skill 11-data-persistence
Clone the repo
git clone --depth 1 https://github.com/wangjianqi/AppStore

Made for: Claude Code, Codex.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for data-persistence

README.md
[![agentmods](https://agentmods.dev/badge/skills/wangjianqi/appstore/11-data-persistence.svg)](https://agentmods.dev/skills/wangjianqi/appstore/11-data-persistence)
Your own site
<a href="https://agentmods.dev/skills/wangjianqi/appstore/11-data-persistence"><img src="https://agentmods.dev/badge/skills/wangjianqi/appstore/11-data-persistence.svg" alt="Measured on agentmods" height="20"></a>
Per session 40 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 3,077 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 1 finding. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00040 $0.03077
Opus 5 $0.00020 $0.01538
Sonnet 5 $0.00008 $0.00615
Haiku 4.5 $0.00004 $0.00308

Measured 5d ago against content hash aafa05ad2cc5, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

data-persistence scanned grade A with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 5d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Makes network callslowCapability

Not a fault in itself. Listed so you know the mod talks to something, and to what.

return try context.fetch(request).first
ios-claude-skills/11-data-persistence/SKILL.md · 348 lines

How it starts

The opening of the file, as written. The whole thing — 348 lines — stays where its author put it; the contents beside it link to each section on GitHub.

数据持久化 / 存储层

存储方案选型

方案 适用场景 线程安全 数据量
UserDefaults 轻量配置、用户偏好 ✅ 主线程安全 < 1MB
Keychain Token、密钥、敏感凭证 极小
CoreData 结构化关系数据、离线缓存 需配置
SwiftData 新项目结构化数据(iOS 17+)
FileManager 文件、图片、导出数据 需加锁 任意

选择原则:

  • 能用 UserDefaults 解决的不上 CoreData
  • 敏感数据(Token、密码)必须存 Keychain,禁止存 UserDefaults
  • 新项目且最低支持 iOS 17+ 可选 SwiftData,否则用 CoreData
  • 文件类数据(导出 PDF、录音文件)用 FileManager

UserDefaults

规范

  • 封装为 UserDefaultsStorage,禁止在业务代码中直接调用 UserDefaults.standard
  • Key 统一管理,禁止散落字符串:
struct UserDefaultsStorage {
    private let defaults = UserDefaults.standard

    enum Key: String {
        case hasCompletedOnboarding
        case selectedTheme
        case lastSyncTimestamp
        case launchCount
    }

    var hasCompletedOnboarding: Bool {
        get { defaults.bool(forKey: Key.hasCompletedOnboarding.rawValue) }
        set { defaults.set(newValue, forKey: Key.hasCompletedOnboarding.rawValue) }
    }
}

已知陷阱

  • bool(forKey:) 在 key 不存在时返回 false,无法区分"未设置"和"设置为 false"。需要区分时用 object(forKey:) != nil 判断
  • UserDefaults.standard 写入是异步的,synchronize() 在 iOS 12+ 已无必要(系统自动处理)
  • 禁止存储大数据(图片 Base64、JSON 数组等),会导致启动变慢
  • App Group 共享:必须用 UserDefaults(suiteName: "group.com.app.shared")

Keychain

封装

final class KeychainStorage {
    static let shared = KeychainStorage()

    private let service = Bundle.main.bundleIdentifier ?? "com.app.default"

    func save(_ data: Data, for key: String) throws {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
        ]
        SecItemDelete(query as CFDictionary)

        var addQuery = query
        addQuery[kSecValueData as String] = data
        addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
        let status = SecItemAdd(addQuery as CFDictionary, nil)
        guard status == errSecSuccess else {
            throw KeychainError.saveFailed(status)
        }
    }

    func load(for key: String) -> Data? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        return status == errSecSuccess ? result as? Data : nil
    }

    func delete(for key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
        ]
        SecItemDelete(query as CFDictionary)
    }
}

Read the full file on GitHub · 348 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 5d ago First seen · 348 lines · 40 tokens per session scan A aafa05ad2cc5

Subscribe to this mod's changes

data-persistence is a skill published in the GitHub repository wangjianqi/AppStore (11 stars, last pushed 3mo ago), licensed MIT. It adds 40 tokens to every session and 3,077 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 1 finding (makes network calls). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.

Related

Other skills, from other repositories

boutique-store

Create and use Boutique Store for Swift data persistence, including initialization, @Stored controllers, CRUD operations, operation chaining, and granular event monitoring. Use when persisting arrays of items, building data controllers, or working with Boutique's Store type.

mergesort/Boutique · 52 tokens

boutique-stored-values

Persist individual values with Boutique's @StoredValue (UserDefaults) and @SecurelyStoredValue (Keychain), including set, reset, toggle, bindings, keypath setters, array and dictionary helpers, and async observation. Use when storing preferences, settings, feature flags, or sensitive data like auth tokens.

mergesort/Boutique · 68 tokens

sqldelight-patterns

SQLDelight for Kotlin Multiplatform shared persistence - .sq files in commonMain, platform drivers (AndroidSqliteDriver on Android, NativeSqliteDriver on iOS), type adapters, migrations, and a shared database accessed from common code. Use for multiplatform or shared persistence. For Android-only Room use…

TalissonVitorino/kmp-ios-skills · 73 tokens

room-patterns

Room persistence for the Android target (androidx.room) - @Entity, @Dao, RoomDatabase, migrations, TypeConverters, and Flow-returning queries. Android-side database. For shared/multiplatform persistence in commonMain use sqldelight-patterns. For the broader Android data layer (Repository pattern, Room plus remote…

TalissonVitorino/kmp-ios-skills · 85 tokens

core-data

Core Data for iOS persistence. Data models, fetch requests, background contexts, and SwiftData migration.

TalissonVitorino/kmp-ios-skills · 24 tokens

swiftdata

Apple SwiftData for iOS 17+ persistence - the @Model macro, ModelContainer and ModelContext, the @Query property wrapper with.

TalissonVitorino/kmp-ios-skills · 31 tokens