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.
npx agentmods add skills/wangjianqi/appstore/11-data-persistencenpx skills add wangjianqi/AppStore --skill 11-data-persistencegit clone --depth 1 https://github.com/wangjianqi/AppStoreWrote 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.
[](https://agentmods.dev/skills/wangjianqi/appstore/11-data-persistence)<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>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.
| Model | Per session | Once 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 |
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 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)
}
}
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.
- 5d ago First seen · 348 lines · 40 tokens per session scan A aafa05ad2cc5
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.
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.
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.
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…
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…
core-data
Core Data for iOS persistence. Data models, fetch requests, background contexts, and SwiftData migration.
swiftdata
Apple SwiftData for iOS 17+ persistence - the @Model macro, ModelContainer and ModelContext, the @Query property wrapper with.