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…
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.
/codemod-patternsContext 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
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
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…
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…
Autonomous, report-only documentation review for Mastra docs. Use when auditing changed docs against source, validating contextual code examples or API…
Convert existing docs diagram images to Mermaid, and author new Mermaid diagrams for Mastra docs. Use when replacing an Excalidraw or PNG/JPG/SVG diagram with…
REQUIRED when modifying any file in packages/playground-ui or packages/playground. Triggers on: React component creation/modification/refactoring, UI changes,…
Review open mastra-ai/mastra GitHub issues, identify direct @mastra/core bugs, and apply the @mastra/core label. Use when auditing issues for core ownership,…