Skip to content
Development
Skill

/codemod-patterns

This guide helps AI agents efficiently create codemods with optimal performance and consistency

From plugin
mastra
27k30 skills14 commands
Install
$ npx -y skills add mastra-ai/mastra --skill codemod-patterns --agent claude-code

How 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.md

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

Read more
Ships withmastra

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.

Get the whole plugin

Other skills on mastra.