Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Cloudkit Schema Source Of Truth

ASecurity

Committed `.ckdb` as the CloudKit schema source of truth, with `xcrun cktool` export / validate / import against Development and Production promotion kept as a Console-only gate. Use when a CloudKit-backed persistence layer adds or edits a record type, field, or index; before any Production schema deploy; or when asked "how do I push CloudKit schema to Production", "why can''t cktool deploy to prod", "why is a field silently missing in Production". Does NOT own the Swift persistence seam → sw...

18 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentrustgoswiftshellsqltestinggitapidatabasesecurity

Works with

terminalcliapi

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add wei18/apple-dev-skills --skill cloudkit-schema-source-of-truth --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cloudkit Schema Source Of Truth?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Cloudkit Schema Source Of Truth
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wei18-cloudkit-schema-source-of-truth/badge)](https://www.skillsdirectory.com/skills/wei18-cloudkit-schema-source-of-truth)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: cloudkit-schema-source-of-truth
description: 'Committed `.ckdb` as the CloudKit schema source of truth, with `xcrun cktool` export / validate / import against Development and Production promotion kept as a Console-only gate. Use when a CloudKit-backed persistence layer adds or edits a record type, field, or index; before any Production schema deploy; or when asked "how do I push CloudKit schema to Production", "why can''t cktool deploy to prod", "why is a field silently missing in Production". Does NOT own the Swift persistence seam → swift-dependency-injection, or token storage → apple-public-repo-security.'
---

# CloudKit Schema Source of Truth

CloudKit has no migration-file system like a SQL database. The schema lives in Apple's
CloudKit Dashboard/Console, and `xcrun cktool` (Apple's official CLI, ships with Xcode) can
export, validate, and import it — but only against the **Development** environment.
Production promotion is a manual, irreversible Console action. This skill makes the
Development side of that workflow scriptable and commit-trackable while keeping the
Production gate correctly user-owned.

## When to invoke

- A persistence change adds, renames, or edits a CloudKit record type, field, or index.
- You need to push schema to a container (Development or Production).
- Before any Production schema deploy — read the safety gate below first.
- Asked why a `.ckdb` file is committed to the repo, or why a field the app writes is missing
  from Production data.

## Scope

Owns: the `.ckdb`-as-source-of-truth workflow, `cktool` invocations against Development, and
the Production promotion gate. Does **not** own: the Swift-side persistence/service code that
reads and writes CloudKit records → `swift-dependency-injection` for how that seam is
injected and faked in tests; secret storage for the management token itself →
`apple-public-repo-security` / `build-time-secret-injection`.

## Prerequisites (one-time, user-owned)

Two credentials, kept in a gitignored env file (e.g. `secrets/.env`, with a committed
`.env.example` template):

- **A CloudKit management token** — generated by a human in CloudKit Dashboard → Settings →
  Tokens → Create Token (Management). This is a privileged credential; treat it like an API
  key with schema-write access, not like a build-time public identifier.
- **The Apple Developer Team ID** (10 characters).

The container identifier itself (e.g. `iCloud.com.example.myapp`) is not secret and can be
hardcoded in tooling.

## Workflow

1. Authenticate `cktool` for this session (positional arg — see gotcha 1 below).
2. Export the live Development schema to the committed source-of-truth file (seed step first: run a debug build once so the app's JIT schema provisions the Development container, THEN export).
3. Pre-flight: validate the committed `.ckdb` against the live container before importing.
4. Deploy to Development — freely runnable and reversible.
5. Always clear the token from `cktool`'s keychain store when done (via a shell `trap ... EXIT` around steps 1–4, so it's purged even if a step fails midway).

Runnable as `${CLAUDE_SKILL_DIR}/scripts/ck-schema-dev.sh` (the `scripts/` folder next to this SKILL.md) — run it by that path or copy it into your repo's `scripts/`; see that file for the exact `cktool` invocations and flags.

## Inputs / outputs

- **Input**: the credentials above, plus either the live Development container (`export`) or
  the committed `cloudkit/<app>.ckdb` (`validate` / `import`).
- **Output**: `export` overwrites `cloudkit/<app>.ckdb` — review the diff, then commit it as
  the schema source of truth. `import` mutates the named container's live schema.
- `.ckdb` files are **not secrets** — they contain schema definitions only, no data or tokens
  — so they're committed like any other source file, distinct from the token itself.

## Safety gate — Production promotion is user-owned, Console-only, irreversible

**`cktool` cannot push schema to Production.** `import-schema --environment production`
rejects with an "endpoint not applicable in this environment" style error, and there is no
promote subcommand. The Development → Production promotion happens **only** in the CloudKit
Console:

1. Bring Development fully in sync first (`import-schema --environment development` above).
2. Console → your container → environment **Development** → Schema → **"Deploy Schema Changes
   to Production…"** → review the generated field/index diff → confirm the deploy.

CloudKit Production record types and fields are **add-only** by Apple's own rule — once
deployed they can't be deleted or renamed, only added to. Indexes are different: they can be
added and removed in Production (WWDC21 "Automate CloudKit tests with cktool and declarative
schema"). Restricting the promotion path to the
Console keeps it naturally user-owned: automation prepares and validates the `.ckdb` and the
Development deploy; a human clicks the actual Production button.

`export` / `validate` / `import --environment development` are all reversible and safe to run
repeatedly without asking anyone.

## Live-run gotchas

1. **`save-token` takes the token as a positional argument, not piped stdin.** Non-interactive
   stdin piping fails with `Error: Interaction was required while running in non-interactive
   mode (CKTOOL_NO_PROMPT=1 or not running in an interactive terminal).` (verified locally,
   cktool 1.0.23001). Brief command-line argv exposure of the token is the tradeoff; purge it
   from the keychain store immediately after (see the `trap` note above).
2. **`validate-schema` requires `--environment` explicitly** — omitting it is a hard error, not
   a default.
3. **`import-schema` only ever targets Development.** Don't assume a script that "runs
   `import-schema --environment production`" has ever actually been exercised — smoke-test any
   such tooling against real credentials before trusting it; a plausible-looking Production
   import path that was never live-tested can sit broken for a long time undetected.
4. **Just-in-time (JIT) schema exists only in Development.** A debug build auto-creates record
   types and fields the first time it writes them, in Development only — Production never does
   this. Corollary: any field the app code writes that was never JIT-seeded in Development
   *before* the last Console promotion is **missing in Production**, and the server returns a
   `CKError` for the unknown field when the app tries to save it — this only *looks* silent if
   the app's own save-completion handling swallows or ignores that error instead of surfacing
   it. **Audit method**: `export-schema --environment production` to a scratch file and diff
   its field set against every field the code actually writes, and confirm every CloudKit save
   call actually surfaces its error instead of discarding it.
5. **JIT marks every field it creates `QUERYABLE SEARCHABLE SORTABLE`.** A hand-authored
   `.ckdb` should declare the **minimal** index set the app's actual queries need instead
   (e.g. only the one field a specific equality query filters on, as `QUERYABLE`) — every index
   adds query/storage cost and noise to the `.ckdb` diff, so start minimal and add indexes as
   real queries need them.
6. **`import-schema` is a declarative import**, so a `.ckdb` can be hand-authored from scratch —
   no Dashboard clicking, no live seed build required. Use one `export`'s output as the syntax
   template (it includes the system `"___*"` fields and the `GRANT` block a hand-written file
   also needs).

For other `cktool` subcommands/flags not required for the core loop above (e.g. `import-schema
--validate`, `export-schema --output-file <path>`), run `xcrun cktool help` / `xcrun cktool
<subcommand> --help` — the offline, primary source, more current than any WWDC talk. One flag
worth knowing without opening a shell: `reset-schema` resets a container's Development
environment to match Production **and deletes all Development data** — a "start clean and
re-seed" tool, not part of the routine loop.

## Idempotency

- `export`: re-running always overwrites `cloudkit/<app>.ckdb` with the current Development
  schema — treat the file as generated + reviewed, not hand-edited, whenever a live export is
  the intended source.
- `import`: CloudKit's import is declarative — re-applying the same unchanged `.ckdb` is a
  no-op.

## Rationale

Treating one `.ckdb` per app as the schema source of truth gives CloudKit the same
review-before-merge discipline a SQL migration file gets, despite CloudKit having no native
migration mechanism. Restricting the token to Development-only tooling, and Production to a
Console click, matches Apple's own irreversibility constraint (add-only fields) to a
correspondingly irreversible, deliberately manual approval step.

## Deviation considerations

- **A container with no meaningful schema evolution** (fixed at launch, never touched again):
  a single manual export is enough; the ongoing export/validate/import loop isn't worth
  automating for a container that never changes.
- **Multiple apps sharing one CloudKit container**: keep one `.ckdb` per container (not per
  app) and make the ownership of shared record types explicit in its surrounding docs, so two
  apps don't independently "fix" the same field in diverging ways.

## Common Mistakes

1. **Assuming `import-schema --environment production` works** because it's syntactically
   accepted-looking — it is Development-only; Production is Console-only.
2. **Skipping the Development JIT-seed step before an export** — the export then reflects an
   incomplete schema, and the gap resurfaces later as a Production write returning `CKError`
   for the unknown field, which looks like a silent failure only if that error is discarded.
3. **Leaving the management token in `cktool`'s keychain store** after a session — purge it
   even on script failure via a `trap`.
4. **Hand-editing `.ckdb` opportunistically** without re-validating against the live
   Development container before importing.
5. **Over-indexing a hand-authored `.ckdb`** (marking every field `QUERYABLE SEARCHABLE
   SORTABLE` out of caution) — every extra index adds query/storage cost and noise to the
   `.ckdb` diff; declare only what the app's queries need and add more later.
6. **Never diffing Production's actual schema against the code's write surface** — the
   missing-field write returns a `CKError` that many apps never surface anywhere visible, so
   the failure mode is only caught by an explicit audit, not by normal testing.

## Review Checklist

- [ ] `.ckdb` is committed under version control; the management token is not.
- [ ] `export` was run after a Development-seeding build, not against a partially-provisioned container.
- [ ] `validate-schema` was run with an explicit `--environment` before any `import`.
- [ ] The management token is purged from `cktool`'s keychain store, even on failure paths.
- [ ] No tooling assumes `import-schema` can target Production — the Console step is documented as the only path.
- [ ] A hand-authored or reviewed `.ckdb` declares only the indexes the app's actual queries need.
- [ ] Production's exported schema has been diffed against the code's write surface at least once since the last Console promotion.

## Related skills

- `swift-dependency-injection` — how CloudKit access is injected and faked, keeping schema concerns out of call sites.
- `swift-testing-baseline` — gate live CloudKit/Game Center access behind a test-only suppression seam; constructing a live container or auth handler inside a test blocks the unentitled SwiftPM runner indefinitely (its "unentitled runner" section covers this landmine — this skill's schema is only ever tested against, never through a live container in CI).
- `apple-public-repo-security` — why the management token is a stricter secret class than a build-time public identifier.
- `build-time-secret-injection` — the general env-file-based secret pattern this workflow's token handling follows.
- Official sources: when verifying or updating a factual or version-sensitive claim, read `references/official-docs.md`.

Attribution

wei18wei18
View sourceMore from wei18 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →