new-migration
Manages registry migrations by enforcing a safe, step-by-step update process for setting keys.
Install
mkdir -p .claude/skills/new-migration && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12238" && unzip -o skill.zip -d .claude/skills/new-migration && rm skill.zipInstalls to .claude/skills/new-migration
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Guided workflow for writing a registry migration in JellyRock when a setting key is renamed, removed, or its data shape changes. Walks docs/dev/registry-migrations.md (pick next version, write migration in source/migrations.bs for the right scope, register the runner, write a real-registry integration test, run on hardware to verify). Use when an existing setting changes shape; brand-new settings don't need migrations and should use /new-setting instead.Key capabilities
- →Confirm if a migration is needed based on setting key changes or data shape changes.
- →Determine the appropriate migration scope (global or user) for the setting.
- →Identify the next available version number for the new migration.
- →Write a migration function to rename, remove, or reshape setting keys.
- →Register the new migration function in the migration runner array.
- →Update downstream code to use the new setting key after migration.
How it works
The skill guides the user through a step-by-step process to create a registry migration in JellyRock, which involves picking a scope, determining a version, writing the migration function, registering it, updating code, and writing tests.
Inputs & outputs
When to use new-migration
- →Renaming setting keys
- →Updating data structures
- →Cleaning up registry settings
About this skill
/new-migration — guided workflow
Wraps docs/dev/registry-migrations.md as a step-by-step. Migrations run in source/main.bs BEFORE any data transformer or session loading; once a migration runs, the registry has only NEW names and downstream code can assume the new shape.
Step 0 — Confirm a migration is needed
You need a migration ONLY when:
- An existing setting key is being renamed (registry name changes).
- An existing setting key is being removed (cleanup).
- A setting's data shape is changing (e.g., string → JSON-encoded object, or one field split into two).
You DO NOT need a migration when:
- Adding a brand-new setting (defaults flow from
settings.jsonautomatically; existing users get the default the first time they touch the new field). Use/new-settinginstead. - Changing a setting's default value (existing users keep their saved value; new users get the new default).
- Changing UI labels / descriptions (no registry-shape impact).
If none of the migration triggers apply, STOP — don't add a migration.
Step 1 — Pick the migration scope
JellyRock runs two migration loops in sequence:
- Global migrations (
runGlobalMigrations()) — operate on theJellyRockregistry section (device-level). Run for global settings, dev flags, and cross-user state. - User migrations (
runRegistryUserMigrations()) — operate on each user's registry section. Run per-user at session-load time.
Pick the matching scope based on which section your setting lives in. If you're not sure, the User Settings screen is per-user (use user migrations); the Global Settings screen is per-device (use global migrations).
Step 2 — Determine the next version number
Read source/migrations.bs and find the highest existing migration version in your scope. The next migration is prevMax + 1.
Migration versions are stored in the registry under a known key (see the doc) so the runner knows which migrations to skip on subsequent runs.
Step 3 — Write the migration function
The migration function takes the registry section (a roRegistrySection) and applies the change. Common shapes:
Rename:
sub migrateRenameAutoplay(section as object)
oldVal = section.Read("autoplay")
if oldVal <> "" then
section.Write("playbackAutoplayEnabled", oldVal)
section.Delete("autoplay")
end if
end sub
Remove:
sub migrateDropDeprecatedFlag(section as object)
section.Delete("deprecatedFlag")
end sub
Reshape:
sub migrateSplitVolumeSettings(section as object)
oldVal = section.Read("audioVolume")
if oldVal <> "" then
parsed = ParseJson(oldVal)
section.Write("audioVolumeMain", str(parsed.main))
section.Write("audioVolumeSurround", str(parsed.surround))
section.Delete("audioVolume")
end if
end sub
Always guard against the missing-key case (<empty string> from Read) — partial migrations from interrupted runs are real.
Step 4 — Register the migration
Add the function to the migration runner array in source/migrations.bs at the right index (matches the version number you picked). The runner walks the array in order; missing indices are gaps the runner skips.
Step 5 — Update downstream code
Once the migration runs, the OLD key is gone from registry. Update every reader and writer of the old key to use the new key:
grep -rn "<old-key>" components/ source/ | grep -v migrations.bs
The migration file itself keeps the old key name (that's where the rename lives) — every other reference should use the new name.
Step 6 — Write a registry-isolated integration test
Per tests/CLAUDE.md: integration tests for migrations live in tests/source/integration/migration/. Use a test- prefixed registry section (the BaseTestSuite clears test-* between tests automatically when m.needsRegistrySetup = true).
The test should:
- Pre-write the OLD key to a
test-*section. - Invoke the migration function directly.
- Assert the OLD key is gone.
- Assert the NEW key has the migrated value.
Don't mock the registry — use a real roRegistrySection. The integration is the point.
Step 7 — Run on hardware to verify
npm run test:integration
The integration suite runs on the Roku and exercises real registry I/O. If hardware isn't reachable, say so explicitly — migrations that pass build but fail at runtime are a real risk.
Step 8 — Capture the rename in a decisions.md entry (optional)
If the rename is non-obvious (e.g., the new name is shorter or follows a new convention), invoke /log decision with a slug like rename-<old>-to-<new> so future-you knows why.
Common pitfalls (from the doc)
- Forgetting to update downstream readers — the migration moves the data but readers still try to read the old key, getting empty strings. Test on hardware to catch.
- Not handling the missing-key case — a partially-completed prior migration can leave the registry in an unexpected state.
- Mocking the registry in tests — defeats the integration. Use real
test-*sections. - Skipping
m.needsRegistrySetup = true— cross-test leakage masks real failures.
When NOT to use
- Brand-new setting →
/new-setting, not/new-migration. - Changing a default value → no migration needed, just update
settings/settings.json. - UI label / description change → no migration needed.
Sub-agent invocation
To invoke from a sub-agent: parent passes Read .claude/skills/new-migration/SKILL.md and follow the steps for $ARGUMENTS=<rename-or-removal-description>; surface each step's diff but do NOT commit in the Task prompt.
When not to use it
- →When adding a brand-new setting.
- →When changing a setting's default value.
- →When changing UI labels or descriptions.
Limitations
- →Migrations are only needed for renaming, removing, or reshaping existing setting keys.
- →The skill does not apply to brand-new settings.
- →The skill does not apply to changes in default values or UI labels.
How it compares
This skill provides a structured, step-by-step workflow for creating registry migrations, ensuring all necessary components like scope, versioning, and testing are addressed, unlike an unguided manual process.
Compared to similar skills
new-migration side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| new-migration (this skill) | 0 | 1mo | Review | Intermediate |
| drizzle | 238 | 2mo | No flags | Intermediate |
| drizzle-orm | 32 | 2mo | No flags | Intermediate |
| database-design | 6 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jellyrock
View all by jellyrock →You might also like
drizzle
lobehub
Drizzle ORM schema and database guide. Use when working with database schemas (src/database/schemas/*), defining tables, creating migrations, or database model code. Triggers on Drizzle schema definition, database migrations, or ORM usage questions.
drizzle-orm
EpicenterHQ
Drizzle ORM patterns for type branding and custom types. Use when working with Drizzle column definitions, branded types, or custom type conversions.
database-design
davila7
Database design principles and decision-making. Schema design, indexing strategy, ORM selection, serverless databases.
prisma-expert
davila7
Prisma ORM expert for schema design, migrations, query optimization, relations modeling, and database operations. Use PROACTIVELY for Prisma schema issues, migration problems, query performance, relation design, or database connection issues.
database-schema-designer
davila7
Design robust, scalable database schemas for SQL and NoSQL databases. Provides normalization guidelines, indexing strategies, migration patterns, constraint design, and performance optimization. Ensures data integrity, query performance, and maintainable data models.
database-migration
wshobson
Execute database migrations across ORMs and platforms with zero-downtime strategies, data transformation, and rollback procedures. Use when migrating databases, changing schemas, performing data transformations, or implementing zero-downtime deployment strategies.