| name | plugin-migration |
| description | Create or review Rock RMS plugin migrations (hotfixes) in Rock/Plugin/HotFixes/. Plugin migrations are single .cs files with sequential numbering and a [MigrationNumber] attribute. Use when the user says "create a plugin migration", "plugin migration", "hotfix migration", "new hotfix", "write a hotfix", "review plugin migration", "check this hotfix", "audit hotfix migration", or needs to create a data fix, configuration change, attribute update, or stored procedure update that ships as a plugin migration. Also use when the user describes a fix or change that targets Rock/Plugin/HotFixes/. Do NOT use for EF migrations in Rock.Migrations/ — use /migration instead. Do NOT use for standalone SQL scripts — use /sql instead. |
| argument-hint | Describe what the plugin migration should do, or say 'review' to review an existing one (e.g., 'fix the HTML content for the SQL runner warning block') |
| compatibility | Requires Claude Code with access to the Rock RMS codebase. |
| metadata | {"version":"1.3","author":"Maxwell Eley"} |
Rock RMS Plugin Migration Creator & Reviewer
You are creating or reviewing a plugin migration (hotfix) in the Rock RMS codebase. Plugin migrations are single .cs files in Rock/Plugin/HotFixes/ with sequential numbering and a [MigrationNumber] attribute. They inherit from Rock.Plugin.Migration and provide Up() and Down() methods.
The user's request: $ARGUMENTS
Reference Routing Table
Load reference files progressively — only when needed.
| Reference File | Load When |
|---|
references/hotfix-patterns.md | Before writing migration logic (always in write mode) |
references/methods-and-sql.md | When choosing methods, writing SQL, or working with stored procedures |
references/common-pitfalls.md | Before finalizing any migration — both write and review modes |
Do NOT read all files upfront. Read hotfix-patterns.md always for write mode; read others only when their trigger condition is met.
Step 1 — Understand the Request and Determine Mode
Parse what the migration needs to do and determine which mode to use:
Write mode — The user describes what the migration should accomplish, or says "create", "write", "new". Proceed to Step 2 (Write Mode).
Review mode — The user says "review", "check", "audit", or names an existing migration file. Proceed to Step 2 (Review Mode).
Migration categories (for write mode):
- Data fix — UPDATE/INSERT/DELETE records to correct bad data
- Configuration change — update page layouts, block settings, HTML content
- Attribute update — add/modify block type attributes, person attributes, defined values
- Stored procedure update — create or alter a stored procedure
- Post-update job — add a run-once service job
- Block type change — add/update/remove block types and entity types
If ambiguous, ask clarifying questions before proceeding.
Write Mode
Step 2 — Determine Migration Number and Version
-
Scan Rock/Plugin/HotFixes/ for the highest existing migration number:
Glob: Rock/Plugin/HotFixes/*.cs
Parse the leading number from each filename (e.g., 279_MigrationRollupsForV18_3_0_1.cs → 279).
-
Next number = highest + 1
-
Determine minimum Rock version:
- If the user specifies a version, use it
- If working on a specific release branch, use that version
- If unclear, ask the user
-
Generate filename: {number}_{PascalCaseDescription}.cs
- Class name = the PascalCase description (without the number prefix)
Step 3 — Research the Schema
Before writing the migration, you must understand the actual database schema. Do not guess column names, types, or relationships.
Read the model files for every entity you're touching:
- Entity models:
Rock/Model/[Domain]/[Entity]/[Entity].cs
- If not found, search:
Rock/Model/**/{EntityName}.cs
- Look for:
[Required] (NOT NULL), [MaxLength(N)] (string limits), FK navigation properties, enum-typed properties
Understand Rock's standard column patterns:
- Every entity inheriting
Model<T> has: Id (identity), Guid (uniqueidentifier), IsSystem (bit), CreatedDateTime, ModifiedDateTime, CreatedByPersonAliasId, ModifiedByPersonAliasId
- Audit FK columns (
CreatedByPersonAliasId, ModifiedByPersonAliasId) reference [PersonAlias], NOT [Person]
- Campus FK columns typically use
ON DELETE SET NULL
[Order] columns should be calculated from existing max, not hardcoded
Check SystemGuid files: Rock/SystemGuid/{EntityType}.cs for well-known GUIDs
Check enum definitions: Rock.Enums/[Domain]/ for integer values of enum-typed columns
Load references:
- Read
references/hotfix-patterns.md for common patterns and complete examples
- Read
references/methods-and-sql.md if using RockMigrationHelper, stored procedures, or complex SQL
Step 4 — Write the Migration File
Use the following template. The copyright block, namespace, class structure, and XML doc comments must match exactly:
using System;
namespace Rock.Plugin.HotFixes
{
[MigrationNumber( {number}, "{minRockVersion}" )]
public class {ClassName} : Migration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
For available methods (Sql(), SqlScalar(), RockMigrationHelper.*, EF wrappers), SQL formatting rules, string escaping, stored procedure patterns, and code organization conventions, consult references/methods-and-sql.md.
Step 5 — Validate
Read references/common-pitfalls.md and run through the pre-finalization checklist before presenting.
Output: Write the .cs file to Rock/Plugin/HotFixes/ and show the contents in conversation for review.
Review Mode
Step 2 (Review Mode) — Find the Migration
- If
$ARGUMENTS names a specific file or migration number, find it in Rock/Plugin/HotFixes/
- Otherwise, find the most recently created .cs file (highest number prefix):
Glob: Rock/Plugin/HotFixes/*.cs
- Read the full .cs file
Step 3 (Review Mode) — Research for Comparison
Before reviewing, gather the context needed to judge correctness:
- Read the actual model files (
Rock/Model/[Domain]/[Entity]/[Entity].cs) for every entity the migration touches — verify column types, [Required], [MaxLength], nullable, FK navigation properties
- Check
Rock/SystemGuid/ files if the migration references GUIDs
- Check
Rock.Enums/[Domain]/ if the migration uses enum integer values
- Read
references/hotfix-patterns.md for expected patterns
- Read
references/common-pitfalls.md for known failure modes
Step 4 (Review Mode) — Audit the Migration
Run through the pre-finalization checklist from references/common-pitfalls.md, plus these additional review-specific checks:
Structural checks
- Class inherits
Rock.Plugin.Migration
- Copyright header and XML doc comments present
[MigrationNumber] attribute present with valid number and version
Cross-reference checks
- If migration references SystemGuid constants, verify they exist
- If migration uses RockMigrationHelper methods, verify parameter order matches method signatures
- Check for potential conflicts with other recent migrations
Step 5 (Review Mode) — Report Findings
Present findings using severity levels:
| Severity | Meaning | Examples |
|---|
| CRITICAL | Must fix — will cause errors or data loss | Wrong block type method, missing string escaping, SQL syntax error |
| WARNING | Should fix — could cause issues or violates conventions | Missing IF NOT EXISTS guard, magic string GUIDs, wrong GUID casing |
| NOTE | Consider — minor improvement or style suggestion | Missing XML doc comment, could use private const string for repeated GUIDs |
Format each finding as:
[SEVERITY-N] Short title
Description of the issue and what to change.
Line/area: [where in the file]
End with a summary: total findings by severity and a go/no-go recommendation.
If the migration is clean: Say so. Don't invent issues to fill a report.
Examples
Example 1: Fix HTML content
User says: "Fix the SQL runner warning block HTML to use proper Bootstrap classes"
Actions:
- Determine next migration number
- Research the HtmlContent entity model
- Write Sql() with UPDATE on [HtmlContent] by known Guid
Result: File written to Rock/Plugin/HotFixes/280_FixSqlRunnerWarningHtml.cs with a Sql() UPDATE on [HtmlContent] targeting the known Guid.
Example 2: Add a block type attribute
User says: "Add a 'ShowHeader' boolean attribute to the PersonBio block type"
Actions:
- Look up PersonBio block type Guid in SystemGuid
- Use RockMigrationHelper.AddOrUpdateBlockTypeAttribute()
Result: File written with RockMigrationHelper.AddOrUpdateBlockTypeAttribute() call using the PersonBio block type Guid from Rock/SystemGuid/BlockType.cs.
Example 3: Add a post-update service job
User says: "Add a run-once job to fix broken achievement types from the v18.0 bug"
Actions:
- Add
using Rock.Model; for typeof() reference
- Use RockMigrationHelper.AddPostUpdateServiceJob() with job type, cron expression, and SystemGuid
Result: File written with AddPostUpdateServiceJob() using typeof(Rock.Jobs.PostUpdateJobs.PostV183UpdateAchievementTypes).FullName and the correct SystemGuid.
Example 4: Update a stored procedure
User says: "Update the SynchronizeListRecipients proc to exclude archived members"
Actions:
- Read
references/methods-and-sql.md for stored procedure pattern
- Save/restore ANSI_NULLS and QUOTED_IDENTIFIER
- Drop existing procedure if exists
- Create updated procedure (inline or via HotFixMigrationResource)
Result: File written with the full stored procedure pattern including session setting save/restore and IF EXISTS guard.
Example 5: Review an existing plugin migration
User says: "review my plugin migration" or /plugin-migration review
Actions:
- Find the most recent migration in
Rock/Plugin/HotFixes/
- Read the .cs file
- Enter Review Mode: research models, audit against checklist + common pitfalls
- Report findings by severity (CRITICAL/WARNING/NOTE) with go/no-go recommendation
Result: Severity-based findings report with actionable fix suggestions and a go/no-go recommendation.
Troubleshooting
Migration number conflict: Another developer may have used that number. Re-scan the directory for the latest number after pulling latest.
"Down migrations are not yet supported": This is the standard convention for plugin migrations. Keep the comment in Down() as-is unless the migration has a natural reverse (like stored procedure changes).
Large SQL won't fit inline: For stored procedures or large scripts, use HotFixMigrationResource embedded resources. Add the SQL to the .resx file and reference it as HotFixMigrationResource._NNN_Description_ProcedureName.
RockMigrationHelper method not found: Check Rock/Data/MigrationHelper.cs for the exact method signature and overloads.
String escaping errors at runtime: Single quotes must be doubled in SQL within C# strings ('O''Brien'). Curly braces must be doubled in $@"..." strings ({{, }}). See references/common-pitfalls.md for full examples.
Wrong block type method (data loss risk): Never use UpdateBlockTypeByGuid() for Obsidian or Mobile blocks — it can delete entity-based block types. Use AddOrUpdateEntityBlockType() instead. See references/common-pitfalls.md for details.
Missing using Rock.Model;: Required when using typeof() for job types or entity types. Without it, the type reference may not resolve correctly.