/codemod-patterns
This guide helps AI agents efficiently create codemods with optimal performance and consistency
$ npx -y skills add mastra-ai/mastra --skill codemod-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/codemod-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
This guide helps AI agents efficiently create codemods with optimal performance and consistency
SKILL.md
codemod-patterns.SKILL.mdThis guide helps AI agents efficiently create codemods with optimal performance and consistency
Quick Reference: Scaffold, Create Fixtures, Run Failing Test, Implement, Verify
Always optimize for minimal AST traversals Use shared functions src/codemods/lib/utils.ts Combine multiple operations early returns when no changes needed Track instances once, reuse the Set
Available Utility Functions trackClassInstances trackMultipleClassInstances renameMethod / renameMethods transformMethodCalls renameImportAndUsages transformConstructorProperties transformObjectProperties
1 Scaffold the Codemod cd packages/codemod pnpm scaffold <codemod-name> Use the codemod name WITHOUT the v1/ prefix. scaffold script automatically adds it Example pnpm scaffold evals-run-experiment NOT v1/evals-run-experiment This creates $ = codemod name src/codemods/v1/$.ts implementation src/test/$.test.ts src/test/**fixtures**/$.input.ts src/test/**fixtures**/$.output.ts Updates src/lib/bundle.ts automatically
2 Test Fixtures
ALWAYS base fixtures on migration guide examples
Input Template // @ts-nocheck // POSITIVE TEST CASE - Should transform // Example from migration guide showing the OLD code const example = oldPattern(); // Multiple occurrences to test const example2 = oldPattern(); // NEGATIVE TEST CASE - Should NOT transform // Unrelated code with similar names/patterns const otherObj = { oldPattern: () => 'different', }; otherObj.oldPattern(); // Should remain unchanged // NEGATIVE TEST CASE - Different instance type class MyClass { oldPattern() { return 'should not change'; } } const myInstance = new MyClass(); myInstance.oldPattern(); // Should remain unchanged
Output Template
// @ts-nocheck // POSITIVE TEST CASE - Should transform // Example from migration guide showing the NEW code const example = newPattern(); // Multiple occurrences to test const example2 = newPattern(); // NEGATIVE TEST CASE - Should NOT transform // Unrelated code remains EXACTLY the same const otherObj = { oldPattern: () => 'different', }; otherObj.oldPattern(); // Unchanged // NEGATIVE TEST CASE - Different instance type class MyClass { oldPattern() { return 'should not change'; } } const myInstance = new MyClass(); myInstance.oldPattern(); // Unchanged
Rules ALWAYS include negative test cases Copy examples DIRECTLY from guides change what the migration guide says to change Ensure negative test cases remain IDENTICAL both input output
3 TDD
pnpm test <codemod-name> Test should FAIL showing difference between actual output unchanged and expected output
validates fixtures are correct test infrastructure works proper understanding
4 Implementation
Patterns A. Method Rename on Tracked Instances (Using Utils) usecase Rename specific class instance methods (Mastra Workflow Memory Agent Storage etc)
Example mastra.getScorers() → mastra.listScorers()
import { createTransformer } from '../lib/create-transformer'; import { trackClassInstances, renameMethod } from '../lib/utils'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; // Track instances efficiently using shared utility const instances = trackClassInstances(j, root, 'Mastra'); // Early return if no instances found if (instances.size === 0) return; // Rename method efficiently const count = renameMethod(j, root, instances, 'getScorers', 'listScorers'); if (count > 0) { context.hasChanges = true; context.messages.push(`Renamed getScorers to listScorers on ${count} Mastra instance(s)`); } });
For multiple renames import { trackClassInstances, renameMethods } from '../lib/utils'; const instances = trackClassInstances(j, root, 'Agent'); if (instances.size === 0) return; const count = renameMethods(j, root, instances, { generateVNext: 'generate', streamVNext: 'stream', });
B. Import Path Transformation usecase Change import paths Example @mastra/evals/scorers/llm → @mastra/evals/scorers/prebuilt
import { createTransformer } from '../lib/create-transformer'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; const oldPaths = ['@mastra/evals/scorers/llm', '@mastra/evals/scorers/code']; const newPath = '@mastra/evals/scorers/prebuilt'; // Find and update import declarations root.find(j.ImportDeclaration).forEach(path => { const source = path.value.source.value; if (typeof source === 'string' && oldPaths.includes(source)) { path.value.source.value = newPath; context.hasChanges = true; } }); if (context.hasChanges) { context.messages.push('Updated import paths to scorers/prebuilt'); } });
C. Import Rename Using Utils
usecase Rename both import and all usages of identifier Example runExperiment → runEvals
import { createTransformer } from '../lib/create-transformer'; import { renameImportAndUsages } from '../lib/utils'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; // Single utility function handles import + all usages efficiently const count = renameImportAndUsages(j, root, '@mastra/core/evals', 'runExperiment', 'runEvals'); if (count > 0) { context.hasChanges = true; context.messages.push('Renamed runExperiment to runEvals'); } });
D. Type Rename
Example MastraMessageV2 → MastraDBMessage
import { createTransformer } from '../lib/create-transformer'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; const oldTypeName = 'MastraMessageV2'; const newTypeName = 'MastraDBMessage'; // Track which local names were imported from @mastra/core const importedLocalNames = new Set<string>(); // Transform import specifiers from @mastra/core root .find(j.ImportDeclaration) .filter(path => { const source = path.value.source.value; return typeof source === 'string' && source === '@mastra/core'; }) .forEach(path => { path.value.specifiers?.forEach((specifier: any) => { if ( specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === oldTyp
Read more
This guide helps AI agents efficiently create codemods with optimal performance and consistency
Quick Reference: Scaffold, Create Fixtures, Run Failing Test, Implement, Verify
Always optimize for minimal AST traversals Use shared functions src/codemods/lib/utils.ts Combine multiple operations early returns when no changes needed Track instances once, reuse the Set
Available Utility Functions trackClassInstances trackMultipleClassInstances renameMethod / renameMethods transformMethodCalls renameImportAndUsages transformConstructorProperties transformObjectProperties
1 Scaffold the Codemod cd packages/codemod pnpm scaffold <codemod-name> Use the codemod name WITHOUT the v1/ prefix. scaffold script automatically adds it Example pnpm scaffold evals-run-experiment NOT v1/evals-run-experiment This creates $ = codemod name src/codemods/v1/$.ts implementation src/test/$.test.ts src/test/**fixtures**/$.input.ts src/test/**fixtures**/$.output.ts Updates src/lib/bundle.ts automatically
2 Test Fixtures
ALWAYS base fixtures on migration guide examples
Input Template // @ts-nocheck // POSITIVE TEST CASE - Should transform // Example from migration guide showing the OLD code const example = oldPattern(); // Multiple occurrences to test const example2 = oldPattern(); // NEGATIVE TEST CASE - Should NOT transform // Unrelated code with similar names/patterns const otherObj = { oldPattern: () => 'different', }; otherObj.oldPattern(); // Should remain unchanged // NEGATIVE TEST CASE - Different instance type class MyClass { oldPattern() { return 'should not change'; } } const myInstance = new MyClass(); myInstance.oldPattern(); // Should remain unchanged
Output Template
// @ts-nocheck // POSITIVE TEST CASE - Should transform // Example from migration guide showing the NEW code const example = newPattern(); // Multiple occurrences to test const example2 = newPattern(); // NEGATIVE TEST CASE - Should NOT transform // Unrelated code remains EXACTLY the same const otherObj = { oldPattern: () => 'different', }; otherObj.oldPattern(); // Unchanged // NEGATIVE TEST CASE - Different instance type class MyClass { oldPattern() { return 'should not change'; } } const myInstance = new MyClass(); myInstance.oldPattern(); // Unchanged
Rules ALWAYS include negative test cases Copy examples DIRECTLY from guides change what the migration guide says to change Ensure negative test cases remain IDENTICAL both input output
3 TDD
pnpm test <codemod-name> Test should FAIL showing difference between actual output unchanged and expected output
validates fixtures are correct test infrastructure works proper understanding
4 Implementation
Patterns A. Method Rename on Tracked Instances (Using Utils) usecase Rename specific class instance methods (Mastra Workflow Memory Agent Storage etc)
Example mastra.getScorers() → mastra.listScorers()
import { createTransformer } from '../lib/create-transformer'; import { trackClassInstances, renameMethod } from '../lib/utils'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; // Track instances efficiently using shared utility const instances = trackClassInstances(j, root, 'Mastra'); // Early return if no instances found if (instances.size === 0) return; // Rename method efficiently const count = renameMethod(j, root, instances, 'getScorers', 'listScorers'); if (count > 0) { context.hasChanges = true; context.messages.push(`Renamed getScorers to listScorers on ${count} Mastra instance(s)`); } });
For multiple renames import { trackClassInstances, renameMethods } from '../lib/utils'; const instances = trackClassInstances(j, root, 'Agent'); if (instances.size === 0) return; const count = renameMethods(j, root, instances, { generateVNext: 'generate', streamVNext: 'stream', });
B. Import Path Transformation usecase Change import paths Example @mastra/evals/scorers/llm → @mastra/evals/scorers/prebuilt
import { createTransformer } from '../lib/create-transformer'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; const oldPaths = ['@mastra/evals/scorers/llm', '@mastra/evals/scorers/code']; const newPath = '@mastra/evals/scorers/prebuilt'; // Find and update import declarations root.find(j.ImportDeclaration).forEach(path => { const source = path.value.source.value; if (typeof source === 'string' && oldPaths.includes(source)) { path.value.source.value = newPath; context.hasChanges = true; } }); if (context.hasChanges) { context.messages.push('Updated import paths to scorers/prebuilt'); } });
C. Import Rename Using Utils
usecase Rename both import and all usages of identifier Example runExperiment → runEvals
import { createTransformer } from '../lib/create-transformer'; import { renameImportAndUsages } from '../lib/utils'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; // Single utility function handles import + all usages efficiently const count = renameImportAndUsages(j, root, '@mastra/core/evals', 'runExperiment', 'runEvals'); if (count > 0) { context.hasChanges = true; context.messages.push('Renamed runExperiment to runEvals'); } });
D. Type Rename
Example MastraMessageV2 → MastraDBMessage
import { createTransformer } from '../lib/create-transformer'; export default createTransformer((fileInfo, api, options, context) => { const { j, root } = context; const oldTypeName = 'MastraMessageV2'; const newTypeName = 'MastraDBMessage'; // Track which local names were imported from @mastra/core const importedLocalNames = new Set<string>(); // Transform import specifiers from @mastra/core root .find(j.ImportDeclaration) .filter(path => { const source = path.value.source.value; return typeof source === 'string' && source === '@mastra/core'; }) .forEach(path => { path.value.specifiers?.forEach((specifier: any) => { if ( specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === oldTyp
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack. It includes everything you need to go from early prototypes to production-ready applications.
Repo: mastra-ai/mastra
Other skills on mastra.
- /builder-smoke-test
Smoke test the Agent Builder feature branch end-to-end against a hermetic project scaffolded by the skill (linked to the current worktree). Covers workspace reconciliation, stored agents/skills CRUD, ownership, visibility, stars, registry/library Copy flow, picker allowlists,
Open skill - /debugging-difficult-bugs
Use early when debugging a medium or hard bug, especially when tests alone may not reveal the real runtime failure. Trigger this before extended TDD iteration when a bug involves runtime state, ordering, persistence, streaming, concurrency, UI/manual reproduction, external
Open skill - /docs-audit
Interactive documentation quality review for Mastra docs. Use when auditing, reviewing, or critiquing Mastra documentation; checking docs against source code; validating code examples, API accuracy, or property completeness; checking whether docs follow the styleguide and
Open skill - /e2e-tests-studio
REQUIRED when modifying any file in packages/playground-ui or packages/playground. Triggers on: React component creation/modification/refactoring, UI changes, new playground features, bug fixes affecting studio UI. Generates Playwright E2E tests that validate PRODUCT BEHAVIOR,
Open skill - /mastra-docs
Documentation guidelines for Mastra. This skill should be used when writing or editing documentation for Mastra. Triggers on tasks involving documentation creation or updates.
Open skill - /mastra-frontend
How to build Mastra frontend interfaces with the @mastra/playground-ui design system. This skill should be used when creating or modifying any application UI — pages, components, styling, or tokens — in this repo or in an external consumer of the design system. The docs site has
Open skill

