<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Connor Fortin</title><link href="http://world.optimizely.com" /><updated>2026-06-24T17:58:56.0000000Z</updated><id>https://world.optimizely.com/blogs/connor-fortin/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Automated Search &amp; Navigation to Graph Migration with Claude Code</title><link href="https://world.optimizely.com/blogs/connor-fortin/dates/2026/6/automated-search--navigation-to-graph-migration-with-claude-code/" /><id>&lt;p style=&quot;font-size: 1.2rem; color: #555; margin-bottom: 8px; font-weight: 400;&quot;&gt;A Claude Code plugin that scans your S&amp;amp;N codebase, applies Graph SDK transformations, and validates the result. Install once, run one command.&lt;/p&gt;
&lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 32px;&quot;&gt;&lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;CMS 13&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Optimizely Graph&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Migration&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Claude Code&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Automation&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Search &amp;amp; Navigation&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background: linear-gradient(135deg,#f0f4ff 0%,#e8f0fe 100%); border: 1px solid #93c5fd; border-left: 4px solid #2563eb; border-radius: 8px; padding: 10px 28px; margin: 0 0 40px;&quot;&gt;
&lt;h3 style=&quot;margin-top: 0;&quot;&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; Claude Code plugin automates the Search &amp;amp; Navigation to Graph SDK migration.&lt;/strong&gt; It scans your .NET solution for every Find API usage, rewrites the code to use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt;, and validates the result by building the project and attributing compiler errors back to the specific transformation that caused them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Five skills cover the full workflow:&lt;/strong&gt; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; runs the entire pipeline end-to-end, or use the individual skills for more control: &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; discovers all S&amp;amp;N usage and classifies complexity, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; rewrites the code, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt; checks the build, and &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt; handles one-off translations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It understands your codebase structure.&lt;/strong&gt; The scan traces dependency graphs through wrapper classes and DI registrations, so indirect consumers of Find are identified too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You keep control over the hard decisions.&lt;/strong&gt; When a pattern has no direct Graph equivalent (like &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; or custom &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;FilterForVisitor&lt;/span&gt;&lt;/strong&gt; implementations), the plugin generates a decisions file and pauses for your input before continuing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install with two commands&lt;/strong&gt; and the plugin loads on every Claude Code session automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;1. Why This Plugin Exists&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Graph SDK blog post&lt;/a&gt; on Optimizely World covers how to write queries with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt;. If you have not read it yet, start there. It walks through &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Where()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchFor()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Facet()&lt;/span&gt;&lt;/strong&gt;, and the rest of the API that replaces Search &amp;amp; Navigation.&lt;/p&gt;
&lt;p&gt;What the blog post does not cover is the mechanical work of actually migrating a real codebase. A typical Optimizely solution has Search &amp;amp; Navigation calls spread across dozens of files. Some are straightforward &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Search&amp;lt;T&amp;gt;().Filter().GetResult()&lt;/span&gt;&lt;/strong&gt; chains. Others are wrapped behind repository classes, injected through DI containers, or built up conditionally with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.OrFilter()&lt;/span&gt;&lt;/strong&gt; composition. Finding all of that, understanding the dependency graph, and rewriting it file by file takes time that could be spent on the parts of a CMS 13 migration that genuinely require human judgment.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; plugin handles the mechanical part. It is a set of Claude Code skills that scan your solution, apply the known API mappings from the Graph SDK blog post, flag the patterns that need human decisions, and validate the result against the compiler. You stay in control of architecture questions. The plugin handles the find-and-replace at scale.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;2. Getting Started&lt;/h2&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;You need Claude Code installed and a .NET solution that currently uses the Search &amp;amp; Navigation (EPiServer Find) SDK.&lt;/p&gt;
&lt;p&gt;Before running the migration, check out a dedicated branch with no pending changes. The solution should build cleanly and all tests should pass. This gives the plugin a clean baseline so it can distinguish migration-introduced errors from pre-existing issues.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Run these two commands in Claude Code:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/plugin marketplace add episerver/content-graph-sdk-migrations
/plugin install cg-migrate@content-graph-sdk-migrations&lt;/pre&gt;
&lt;p&gt;The plugin loads automatically on every subsequent Claude Code session. No configuration files to edit.&lt;/p&gt;
&lt;h3&gt;What Gets Installed&lt;/h3&gt;
&lt;p&gt;The plugin adds five slash commands to your Claude Code session:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Command&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Run the full migration pipeline end-to-end: scan, transform, validate, and fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Discover all S&amp;amp;N usage across the solution and produce a migration manifest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Translate a single file or code snippet from S&amp;amp;N to Graph SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Apply transformations to all files identified by the scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Build the project and map each compiler error back to the transformation that caused it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Three Ways to Use the Plugin&lt;/h3&gt;
&lt;p&gt;You do not have to use all five commands. Pick the approach that fits where you are in your migration:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Approach&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Commands&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;Full pipeline&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to migrate the entire solution end-to-end in one run. The command handles scan, transform, validate, and build-fix phases automatically, pausing only for manual decisions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;Step by step&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; &amp;rarr; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; &amp;rarr; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to review the scan report before transforming, re-run a single phase after making manual edits, or iterate on specific files without restarting the full pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;One-off translation&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to translate a single file or code snippet, understand how a specific S&amp;amp;N pattern maps to the Graph SDK, or handle a file individually before or after a larger migration run.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The rest of this post covers each approach in detail. If you just want to get started, skip to &lt;strong&gt;section 3&lt;/strong&gt; for the full pipeline or &lt;strong&gt;section 5&lt;/strong&gt; for one-off translations.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;3. Running the Full Migration&lt;/h2&gt;
&lt;p&gt;The fastest way to migrate is &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;. It orchestrates the entire pipeline in a single invocation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-all --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;If you omit &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;--project&lt;/span&gt;&lt;/strong&gt;, the plugin searches for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.sln&lt;/span&gt;&lt;/strong&gt; files in the current directory.&lt;/p&gt;
&lt;h3&gt;What Happens&lt;/h3&gt;
&lt;p&gt;The command runs six phases sequentially:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: Scan.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; to discover all Find SDK usage, trace dependency graphs, and classify each pattern by complexity. If no migration targets are found, the command stops early.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: Confirm.&lt;/strong&gt; Presents a summary of what will be transformed automatically and what will require manual decisions, then pauses for your confirmation before making any changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Transform.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; to apply all known API mappings, swap NuGet packages, and flag items for manual review.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Validate.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt; to build the project and attribute compiler errors to specific transformation rules. If errors are found, it automatically retries the transformation on the failed files for a second pass.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5: Build &amp;amp; Fix.&lt;/strong&gt; Rebuilds the project and iteratively fixes remaining compiler errors that have clear automated solutions, such as &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS0266&lt;/span&gt;&lt;/strong&gt; type mismatches, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS1061&lt;/span&gt;&lt;/strong&gt; missing members, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS0246&lt;/span&gt;&lt;/strong&gt; unknown types, and NuGet version conflicts. Errors that require business logic decisions are deferred for you to handle manually.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6: Report.&lt;/strong&gt; Generates a comprehensive migration report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-all/&lt;/span&gt;&lt;/strong&gt; that ties together the results from every phase: targets scanned, files transformed, errors fixed, and remaining manual items with prioritized next steps.&lt;/p&gt;
&lt;p&gt;The final report classifies the migration status as &lt;strong&gt;Complete&lt;/strong&gt; (all errors resolved), &lt;strong&gt;Partial&lt;/strong&gt; (some errors remain), or &lt;strong&gt;Nothing to migrate&lt;/strong&gt; (no targets found).&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #2563eb; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dbeafe;&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;
&lt;p&gt;Use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; for the typical workflow. The individual skills (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;) are still available when you need to re-run a specific phase or want more control over the process.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;4. Scanning Your Codebase&lt;/h2&gt;
&lt;p&gt;If you want to inspect the migration scope before committing to a full run, or if you need to re-run just the scan phase, use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; directly:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-scan --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;If you omit &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;--project&lt;/span&gt;&lt;/strong&gt;, the plugin searches for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.sln&lt;/span&gt;&lt;/strong&gt; files in the current directory.&lt;/p&gt;
&lt;p&gt;The scan runs in four phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: NuGet Detection.&lt;/strong&gt; The scan parses &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.csproj&lt;/span&gt;&lt;/strong&gt; files to find which projects reference &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;EPiServer.Find&lt;/span&gt;&lt;/strong&gt; packages and what versions they use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: Direct Reference Scan.&lt;/strong&gt; Using regex patterns from a built-in registry of 50+ S&amp;amp;N API patterns, the scan locates every file that calls into the Find SDK. Each match is categorized by type (filtering, facets, sorting, search, DI registration, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Dependency Graph Tracing.&lt;/strong&gt; This is where the scan goes beyond simple text search. It follows constructor injection, DI registrations, and wrapper class hierarchies up to 5 hops deep. If you have a &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt; that wraps &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;IClient&lt;/span&gt;&lt;/strong&gt; and a &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchController&lt;/span&gt;&lt;/strong&gt; that injects &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt;, both get flagged as migration targets even though only &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt; contains direct Find API calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Complexity Classification.&lt;/strong&gt; Every identified pattern gets one of three labels:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Classification&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Meaning&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;direct-swap&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;1:1 Graph SDK equivalent exists&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Filter()&lt;/span&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Where()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Take()&lt;/span&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Limit()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;pattern-rewrite&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Needs restructuring but the approach is known&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.OrFilter()&lt;/span&gt;&lt;/strong&gt; composition to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;BuildFilter&amp;lt;T&amp;gt;().Or()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;No automated equivalent, needs human decision&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt;, custom &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;FilterForVisitor&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Scan Output&lt;/h3&gt;
&lt;p&gt;The scan produces a console summary with statistics and a detailed markdown report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-scan/scan-report.md&lt;/span&gt;&lt;/strong&gt;. The report includes every target file, the specific patterns found, the dependency tree, and the complexity breakdown.&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #2563eb; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dbeafe;&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;
&lt;p&gt;Add &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/&lt;/span&gt;&lt;/strong&gt; to your &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.gitignore&lt;/span&gt;&lt;/strong&gt;. This directory is for migration artifacts and should not be committed.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;5. Translating Individual Queries&lt;/h2&gt;
&lt;p&gt;For one-off translations or to understand how a specific pattern maps to the Graph SDK, use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-map&lt;/pre&gt;
&lt;p&gt;Point it at a file or paste a code snippet. The skill applies 17 translation rules covering the full S&amp;amp;N API surface.&lt;/p&gt;
&lt;h3&gt;Before and After&lt;/h3&gt;
&lt;div style=&quot;margin: 16px 0;&quot;&gt;
&lt;div style=&quot;font-size: 0.75rem; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; padding: 6px 14px; border-radius: 8px 8px 0 0; color: #fff; background: #ef4444;&quot;&gt;Before - Search &amp;amp; Navigation&lt;/div&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 0px 0px 8px 8px; padding: 0.5rem; overflow-x: auto; margin: 0px 0px 16px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #000080;&quot;&gt;var&lt;/span&gt; result = searchClient.&lt;span style=&quot;color: #0000cc;&quot;&gt;Search&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #004d40;&quot;&gt;ArticlePage&lt;/span&gt;&amp;gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;For&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;chocolate cake&quot;&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;InField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Title, &lt;span style=&quot;color: #800000;&quot;&gt;3.0&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;InField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Summary, &lt;span style=&quot;color: #800000;&quot;&gt;2.0&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Filter&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category.&lt;span style=&quot;color: #0000cc;&quot;&gt;Match&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;Dessert&quot;&lt;/span&gt;))
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Filter&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.IsPublished.&lt;span style=&quot;color: #0000cc;&quot;&gt;Match&lt;/span&gt;(&lt;span style=&quot;color: #000080;&quot;&gt;true&lt;/span&gt;))
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;TermsFacetFor&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;OrderByDescending&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.PublishDate)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Take&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;10&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Skip&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;20&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;GetResult&lt;/span&gt;();&lt;/pre&gt;
&lt;div style=&quot;font-size: 0.75rem; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; padding: 6px 14px; border-radius: 8px 8px 0 0; color: #fff; background: #16a34a;&quot;&gt;After - Graph SDK&lt;/div&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 0px 0px 8px 8px; padding: 0.5rem; overflow-x: auto; margin: 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #000080;&quot;&gt;var&lt;/span&gt; result = &lt;span style=&quot;color: #000080;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #660033;&quot;&gt;_graphClient&lt;/span&gt;
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;QueryContent&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #004d40;&quot;&gt;ArticlePage&lt;/span&gt;&amp;gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;SearchFor&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;chocolate cake&quot;&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;UsingField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Title, boost: &lt;span style=&quot;color: #800000;&quot;&gt;3&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;UsingField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Summary, boost: &lt;span style=&quot;color: #800000;&quot;&gt;2&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Where&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category &lt;span style=&quot;color: #6b3a00;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #a31515;&quot;&gt;&quot;Dessert&quot;&lt;/span&gt; &lt;span style=&quot;color: #6b3a00;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; x.IsPublished)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Facet&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;OrderBy&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.PublishDate, &lt;span style=&quot;color: #004d40;&quot;&gt;OrderDirection&lt;/span&gt;.Descending)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Limit&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;10&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Skip&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;20&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;IncludeTotal&lt;/span&gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;GetAsContentAsync&lt;/span&gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt; skill is useful for building intuition about the mapping rules before running a full transformation, and for handling files you want to review individually.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;6. Transforming the Full Codebase&lt;/h2&gt;
&lt;p&gt;Once you have reviewed the scan report and understand the scope, run the full transformation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-transform --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;You can optionally pass the scan report path if you have already run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-transform --project path/to/YourSolution.sln --scan-report .cg-migrations/migrate-scan/scan-report.md&lt;/pre&gt;
&lt;h3&gt;How the Transform Works&lt;/h3&gt;
&lt;p&gt;The transform runs in six phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: Decision Resolution.&lt;/strong&gt; For every pattern classified as &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt; in the scan, the transform generates a decisions file at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-decisions.md&lt;/span&gt;&lt;/strong&gt;. This file groups patterns and presents strategy options. The plugin pauses here and asks you to choose a strategy for each group before continuing.&lt;/p&gt;
&lt;p&gt;Example decision groups and strategies:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Pattern Group&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Suggested Strategy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; (searches across multiple content types)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;type-specific-queries&lt;/span&gt;&lt;/strong&gt; (create separate &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;QueryContent&amp;lt;T&amp;gt;()&lt;/span&gt;&lt;/strong&gt; per type)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;ContentIndexer&lt;/span&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Track()&lt;/span&gt;&lt;/strong&gt; calls&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;remove&lt;/span&gt;&lt;/strong&gt; (comment out, no Graph equivalent for direct indexing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Custom site/visitor filters&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;custom-implementation&lt;/span&gt;&lt;/strong&gt; (you provide the replacement logic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.UsingSynonyms()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;per-filter-synonym&lt;/span&gt;&lt;/strong&gt; (move to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Match(&quot;value&quot;, SynonymSlot.One)&lt;/span&gt;&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: NuGet Package Setup.&lt;/strong&gt; Adds &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt; to the relevant projects and tracks the S&amp;amp;N packages for removal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Code Transformation.&lt;/strong&gt; Each file gets 13 transformation steps applied in sequence: namespace updates, DI registration changes, query entry points, full-text search, filtering, sorting, pagination, facets, projections, execution (all made async), result access patterns, manual pattern strategies, and cleanup of orphaned &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;using&lt;/span&gt;&lt;/strong&gt; statements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Cleanup.&lt;/strong&gt; Removes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;using EPiServer.Find&lt;/span&gt;&lt;/strong&gt; statements that are no longer needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5: Build Validation.&lt;/strong&gt; Runs &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;dotnet build&lt;/span&gt;&lt;/strong&gt; and auto-fixes common issues like NuGet conflicts and generic constraint mismatches (the Graph SDK requires &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;where T : class, IContentData&lt;/span&gt;&lt;/strong&gt; rather than just &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;IContentData&lt;/span&gt;&lt;/strong&gt;). Iterates up to 2 cycles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6: Reporting.&lt;/strong&gt; Generates a transform report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-transform/transform-report.md&lt;/span&gt;&lt;/strong&gt; with per-file results.&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #f59e0b; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #fef3c7;&quot;&gt;&lt;strong&gt;The decisions file persists across runs&lt;/strong&gt;
&lt;p&gt;If you run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; again, it reads your previous decisions. You can edit the file directly to change strategies for specific patterns or files.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;7. Validating the Result&lt;/h2&gt;
&lt;p&gt;After the transform completes, run validation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-validate --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;The validation phase does more than just run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;dotnet build&lt;/span&gt;&lt;/strong&gt;. It parses every compiler error, matches it against a built-in lookup table of known migration-related error signatures, and attributes each failure to the specific transformation rule that likely caused it.&lt;/p&gt;
&lt;h3&gt;Validation Output&lt;/h3&gt;
&lt;p&gt;The report separates errors into three buckets:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Bucket&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Migration-caused (high confidence)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;File was transformed AND error matches a known migration pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Possibly migration-related (medium confidence)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Error matches a known cause but the file was not directly transformed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Pre-existing / out-of-scope&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Error does not match any migration pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each error includes the file path, line number, error code, message, and the likely cause with a suggested fix.&lt;/p&gt;
&lt;h3&gt;Example Error Attribution&lt;/h3&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #004d40;&quot;&gt;CS1061&lt;/span&gt; in &lt;span style=&quot;color: #660033;&quot;&gt;SearchService.cs&lt;/span&gt;:&lt;span style=&quot;color: #800000;&quot;&gt;42&lt;/span&gt;
  &lt;span style=&quot;color: #a31515;&quot;&gt;&#39;IContentQuery&amp;lt;ArticlePage&amp;gt;&#39; does not contain a definition for &#39;TotalMatching&#39;&lt;/span&gt;
  Likely cause: Rule 11 (Result Access)
  Suggested fix: Add &lt;span style=&quot;color: #0000cc;&quot;&gt;.IncludeTotal()&lt;/span&gt; to the query chain and access &lt;span style=&quot;color: #0000cc;&quot;&gt;result.Total&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;After reporting, the validation skill offers to re-run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; on just the failed files for a second pass (max 2 rounds). This catches cases where the first pass produced valid but incomplete transformations.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;8. Full Workflow at a Glance&lt;/h2&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 1. Check out a clean branch&lt;/em&gt;&lt;/span&gt;
git checkout -b feature/graph-migration

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 2. Run the full migration&lt;/em&gt;&lt;/span&gt;
/migrate-all --project src/MySolution.sln

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 3. Make decisions for manual patterns when prompted&lt;/em&gt;&lt;/span&gt;

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 4. Review the migration report&lt;/em&gt;&lt;/span&gt;
&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# (open .cg-migrations/migrate-all/*-migration-report.md)&lt;/em&gt;&lt;/span&gt;

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 5. Fix any remaining manual items and commit&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;That is the simplest path. If you need more control, the individual skills (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;) can be run separately and repeated as needed. The decisions file and scan report persist between runs, so you can iterate without losing your choices.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;9. What the Plugin Handles vs. What You Handle&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;The plugin handles&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;You handle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Finding every S&amp;amp;N API call across the solution&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Reviewing the scan report for completeness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Tracing wrapper classes and DI dependency chains&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Deciding strategies for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt; patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Applying the 17 known API translation rules&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Custom filter/visitor logic that has no Graph equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Making methods async when execution changes to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;GetAsync()&lt;/span&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;GetAsContentAsync()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Business logic changes (e.g., if &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; was used to merge results, you decide how to restructure)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Adding generic constraints (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;class, IContentData&lt;/span&gt;&lt;/strong&gt;)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Integration test updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Attributing compiler errors to specific transformation rules&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Verifying that query results are functionally equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;NuGet package additions&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;NuGet package removals (tracked but left for you to confirm)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: none;&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;The plugin&#39;s pattern registry will continue to grow as partners encounter additional S&amp;amp;N patterns during real-world migrations.&lt;/p&gt;
&lt;p&gt;If you run into a Search &amp;amp; Navigation pattern that the plugin does not handle, the validation report will call it out. File an issue on the GitHub repository at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;episerver/content-graph-sdk-migrations&lt;/span&gt;&lt;/strong&gt; so the pattern can be added to the registry.&lt;/p&gt;
&lt;h3&gt;Next Steps&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install the plugin with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/plugin marketplace add episerver/content-graph-sdk-migrations&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; on your solution to migrate end-to-end, or start with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; to preview the scope first&lt;/li&gt;
&lt;li&gt;Review the migration report and fix any remaining manual items&lt;/li&gt;
&lt;li&gt;Read the &lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Graph SDK blog post&lt;/a&gt; to understand the API you are migrating to&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Introducing the Optimizely CMS 13 Graph SDK&lt;/a&gt; (the companion blog post covering the Graph SDK API)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/episerver/content-graph-sdk-migrations&quot;&gt;Plugin Repository: episerver/content-graph-sdk-migrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;border-left: 4px solid #16a34a; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dcfce7;&quot;&gt;&lt;strong&gt;Start with the scan&lt;/strong&gt;
&lt;p&gt;Running &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; is read-only. It does not modify any files. You can run it against any branch at any time to understand the scope of the migration before committing to the transformation.&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;margin-top: 32px; font-size: 0.85rem; color: #888; font-style: italic;&quot;&gt;This guide is based on the &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; Claude Code plugin for migrating Search &amp;amp; Navigation to the Optimizely Graph SDK. The plugin is actively maintained and the pattern registry grows with each release.&lt;/p&gt;</id><updated>2026-06-24T17:58:56.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>