Claude Code Plugins

Community-maintained marketplace

Feedback

Modify Generated Code

@halfdomelabs/baseplate
3
0

Workflow for modifying generated code in Baseplate, including template extraction, generator updates, and project synchronization.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Modify Generated Code
description Workflow for modifying generated code in Baseplate, including template extraction, generator updates, and project synchronization.

Modify Generated Code Skill

Use this skill when modifying code that is generated by Baseplate generators, adding new templates, or updating generator behavior.

Overview

Baseplate follows a code-first development approach:

  1. Make changes directly in working codebases (example projects)
  2. Extract those changes into reusable templates
  3. Update generators to use the new templates
  4. Validate and sync the generated code

Example projects:

  • examples/blog-with-auth - Blog application with authentication
  • examples/todo-with-auth0 - Todo application with Auth0 integration

Documentation References

For detailed documentation on generators, consult these guides via the baseplate-docs MCP:

Guide Document ID Description
Generator Development Guide df804c4d-72f1-4b30-bb4a-cdafac7608d2 Comprehensive guide covering core providers, template rendering, and generator patterns
React Generators Guide 8687772b-b258-4241-9cbe-e73e9d13a203 React-specific providers, Vite configuration, component generation
Fastify Generators Guide 862dcef2-7ff8-4de1-9840-fc73d89f32eb Backend providers, API generation, configuration management
Core Providers Reference 200cfab4-56ea-4f60-880c-fa6b8a18048c Detailed reference for nodeProvider, typescriptFileProvider, etc.

To fetch a guide:

mcp__baseplate_docs__get_document_by_id({
  documentId: 'df804c4d-72f1-4b30-bb4a-cdafac7608d2',
});

Generator Architecture

Important: Never manually edit files in generated/ directories. These are auto-generated by pnpm generate:templates. Only modify:

  • Template source files in templates/ directories
  • extractor.json configuration
  • The main *.generator.ts file

Generator Packages

Generators are organized into three main packages:

Package Location Purpose
@baseplate-dev/core-generators packages/core-generators/src/generators/ Node.js, TypeScript, ESLint, Prettier, Vitest
@baseplate-dev/react-generators packages/react-generators/src/generators/ React, Vite, Apollo, admin UI
@baseplate-dev/fastify-generators packages/fastify-generators/src/generators/ Fastify, Prisma, Pothos, auth, email

Generator Structure

Every generator follows this pattern:

import { createGenerator, createGeneratorTask } from '@baseplate-dev/sync';
import { z } from 'zod';

export const myGenerator = createGenerator({
  name: 'category/my-generator',
  generatorFileUrl: import.meta.url,
  descriptorSchema: z.object({
    // Configuration options
  }),
  buildTasks: (descriptor) => ({
    // Add auto-generated tasks for templates
    paths: MY_GENERATOR_GENERATED.paths.task,
    imports: MY_GENERATOR_GENERATED.imports.task,
    renderers: MY_GENERATOR_GENERATED.renderers.task,

    main: createGeneratorTask({
      dependencies: {
        renderers: MY_GENERATOR_GENERATED.renderers.provider,
      },
      run({ renderers }) {
        return {
          build: async (builder) => {
            await builder.apply(renderers.myTemplate.render());
          },
        };
      },
    }),
  }),
});

Key Providers

Core Providers (from @baseplate-dev/core-generators):

Provider Purpose
nodeProvider Package.json, dependencies, scripts
typescriptFileProvider TypeScript file generation with imports
packageInfoProvider Package name, root path, src path
eslintConfigProvider ESLint configuration
nodeGitIgnoreProvider .gitignore management

React Providers (from @baseplate-dev/react-generators):

Provider Purpose
reactBaseConfigProvider Vite plugins, server options, app configuration
reactPathsProvider React-specific paths (components folder, etc.)

Fastify Providers (from @baseplate-dev/fastify-generators):

Provider Purpose
fastifyProvider Node flags, dev output formatter
fastifyOutputProvider Runtime config (node commands, flags)
configServiceProvider Environment variables with Zod validation

Shared Providers and Scopes

Providers communicate between tasks using scopes:

import { packageScope } from '@baseplate-dev/core-generators';

// Export a provider to package scope (available to entire package)
exports: {
  myProvider: myProviderType.export(packageScope),
}

// Consume a provider from dependencies
dependencies: {
  someProvider: someProviderType,
}

Template Rendering with Renderers

The modern pattern uses auto-generated renderers:

// Renderers are generated from templates in ./templates/ directory
import { MY_GENERATOR_GENERATED } from './generated/index.js';

// Use in tasks
buildTasks: () => ({
  paths: MY_GENERATOR_GENERATED.paths.task,
  imports: MY_GENERATOR_GENERATED.imports.task,
  renderers: MY_GENERATOR_GENERATED.renderers.task,

  main: createGeneratorTask({
    dependencies: {
      renderers: MY_GENERATOR_GENERATED.renderers.provider,
    },
    run({ renderers }) {
      return {
        build: async (builder) => {
          // Simple render
          await builder.apply(renderers.myTemplate.render());

          // Render with variables
          await builder.apply(
            renderers.service.render({
              variables: {
                TPL_SERVICE_NAME: 'UserService',
              },
            }),
          );
        },
      };
    },
  }),
});

Creating New Generators

Use the MCP action to scaffold new generators:

mcp__baseplate_dev_server__create_generator({
  name: 'category/my-generator',
  directory: 'packages/fastify-generators/src/generators',
  includeTemplates: true,
});

Example directories:

  • packages/core-generators/src/generators
  • packages/fastify-generators/src/generators
  • packages/react-generators/src/generators
  • plugins/plugin-storage/src/generators/fastify

This creates:

  • <name>.generator.ts - Main generator with boilerplate
  • index.ts - Barrel export
  • generated/index.ts - Placeholder for generated exports
  • extractor.json - Template extractor configuration

After creating, add templates to the templates/ directory and regenerate the typed template helpers:

mcp__baseplate_dev_server__generate_templates({});

Or via command line:

pnpm generate:templates

Step-by-Step Process

1. Code Development

Make changes in the appropriate example project (e.g., examples/blog-with-auth).

Note: You only need to modify one project at a time.

# Validate changes work
pnpm build && pnpm lint

2. Review Changes with User

Before proceeding with template extraction, pause and allow the user to review the code changes. This ensures:

  • The fixes/features look correct before extracting to templates
  • Any issues can be caught early before they propagate to generators
  • The user understands what will be extracted

IMPORTANT: At this stage, you should ONLY have modified files in the example project (e.g., examples/blog-with-auth). Do NOT modify any generator code (*.generator.ts), template files in templates/ directories, or plugin code until AFTER the user has reviewed and approved the example project changes. Generator modifications happen in Step 5 after template extraction.

3. Template Metadata Management (Optional)

For most cases: Skip this step! Template metadata is automatically preserved when modifying existing template files.

Only manage metadata when:

  • Creating brand new template files
  • Changing fundamental template properties (name, generator, type)
  • Removing template files completely

Check existing metadata:

mcp__baseplate_dev_server__show_template_metadata({
  filePath: 'src/components/my-component.tsx',
  project: 'blog-with-auth',
});

Configure NEW templates only when needed:

// For NEW TypeScript templates
mcp__baseplate_dev_server__configure_ts_template({
  filePath: 'src/components/brand-new-component.tsx',
  generator: '@baseplate-dev/react-generators#core/react',
  templateName: 'brand-new-component',
  project: 'blog-with-auth',
});

// For NEW text templates with variables
mcp__baseplate_dev_server__configure_text_template({
  filePath: 'src/config/new-config.json',
  generator: '@baseplate-dev/core-generators',
  templateName: 'new-config',
  variables: { appName: { value: 'MyApp' } },
  project: 'blog-with-auth',
});

// For NEW raw/binary templates
mcp__baseplate_dev_server__configure_raw_template({
  filePath: 'public/new-icon.ico',
  generator: '@baseplate-dev/core-generators',
  templateName: 'new-icon',
  project: 'blog-with-auth',
});

Delete template completely:

mcp__baseplate_dev_server__delete_template({
  filePath: 'src/components/old-component.tsx',
  project: 'blog-with-auth',
});

4. Template Extraction

Extract templates from your working codebase:

mcp__baseplate_dev_server__extract_templates({
  project: 'blog-with-auth',
  app: 'backend', // or 'web' for frontend
});

This updates the local generator templates based on your code changes.

5. Generator Updates

Back in the repository root:

# Fix any type errors from added/removed variables and templates
pnpm typecheck

# Update generator configurations, schemas, and UI as needed:
# - Wire up new variables in compilers
# - Update schemas in project-builder-web or plugins
# - Add/remove generator logic as needed

# Validate changes
pnpm build && pnpm lint

6. Diff Validation

Check for differences between written and generated code:

mcp__baseplate_dev_server__diff_project({
  project: 'blog-with-auth',
  packages: ['backend'], // or ['web'] for frontend
});

7. Handle Differences

Analyze the diff results:

  • Acceptable differences (import aliases, minor formatting): Can be incrementally fixed using sync-file or ignored
  • Significant differences: Update generators to match written code
  • Intentional differences: Use snapshot system

Incremental fixes with sync-file:

For acceptable differences that you want to eliminate before the final sync, use the sync-file command to apply individual files:

// Apply specific files from generated output
mcp__baseplate_dev_server__sync_file({
  project: 'blog-with-auth',
  app: 'backend',
  files: ['src/routes/users.ts', 'src/models/*.ts'],
});

This writes the generated version directly to both the working directory and baseplate/generated/ folder without performing a full sync. Use this to incrementally clear diffs before running the final overwrite sync in step 8.

Intentional differences are changes that should exist in the example project but NOT be extracted into generators. Common examples:

  • Unit tests specific to the example project
  • Demo data or sample content
  • Example-specific configuration

For files with intentional differences:

// Add files to snapshot
mcp__baseplate_dev_server__snapshot_add({
  project: 'blog-with-auth',
  app: 'backend',
  files: ['src/specific-file.ts'],
});

// For removed files that should stay removed
mcp__baseplate_dev_server__snapshot_add({
  project: 'blog-with-auth',
  app: 'backend',
  files: ['src/removed-file.ts'],
  deleted: true,
});

8. Code Synchronization

Once diffs are acceptable, synchronize the working codebase:

mcp__baseplate_dev_server__sync_project({
  project: 'blog-with-auth',
  overwrite: true,
});

Warning: This will overwrite all files in the project. Before running with overwrite: true:

  • Ensure your diff looks correct (step 6)
  • Consider committing your current changes first, so you can revert if needed

9. Final Validation

// Run final diff to ensure no unexpected changes
mcp__baseplate_dev_server__diff_project({
  project: 'blog-with-auth',
  packages: ['backend'],
});

The diff should show no changes or only expected/snapshotted differences.

10. Sync All Projects

Sync all example projects to apply your generator changes:

mcp__baseplate_dev_server__sync_all_projects({
  overwrite: true,
});

11. Create Changeset

Add a changeset to document the changes for the changelog:

# Create a new changeset file in .changeset/ directory

Example changeset format:

---
'@baseplate-dev/plugin-auth': patch
---

Brief description of the change

- Bullet point details of what changed
- Another detail if needed

Changeset types:

  • patch: Bug fixes, minor changes (most common)
  • minor: New features, non-breaking changes
  • major: Breaking changes

Package names should match the package that was modified (e.g., @baseplate-dev/plugin-auth, @baseplate-dev/fastify-generators, @baseplate-dev/react-generators).

Advanced: Snapshot Management

For complex scenarios with intentional differences:

// View current snapshot status
mcp__baseplate_dev_server__snapshot_show({
  project: 'blog-with-auth',
  app: 'backend',
});

// Remove files from snapshot (let them be generated normally)
mcp__baseplate_dev_server__snapshot_remove({
  project: 'blog-with-auth',
  app: 'backend',
  files: ['src/file.ts'],
});

// Save complete snapshot (overwrites existing)
mcp__baseplate_dev_server__snapshot_save({
  project: 'blog-with-auth',
  app: 'backend',
  force: true,
});

Advanced: Template Management

// Create a new generator
mcp__baseplate_dev_server__create_generator({
  name: 'email/sendgrid',
  directory: 'packages/fastify-generators/src/generators',
  includeTemplates: true,
});

// List current templates
mcp__baseplate_dev_server__list_templates({
  project: 'blog-with-auth',
});

// Generate template files after manual extractor.json changes
mcp__baseplate_dev_server__generate_templates({
  project: 'blog-with-auth',
});

// Remove outdated templates
mcp__baseplate_dev_server__delete_template({
  filePath: 'src/outdated-file.ts',
  project: 'blog-with-auth',
});

Important: When to Stop and Ask for Help

If you encounter issues with core generator logic (e.g., providers not wiring correctly, template rendering issues, or unexpected generation behavior), stop and highlight the issue for the user rather than trying to hack around it. These issues often indicate deeper problems that need proper resolution.

Troubleshooting

Type Errors After Template Extraction

  • Check that all template variables are properly defined in generators
  • Ensure import providers are correctly configured
  • Run pnpm typecheck to identify specific issues

Diff Conflicts

  • Use snapshot_add to add resolved files to snapshot
  • For manual conflicts, edit files and re-add to snapshot
  • Consider if differences indicate generator bugs vs. intentional customizations

Import Alias Differences

  • Differences in relative paths vs. import aliases are acceptable as long as they resolve to the same file (e.g., ../components/button.ts vs @src/components/button.ts)
  • Use snapshots if these differences are intentional and should be preserved
  • Update generators if aliases should be standardized

Best Practices

  1. Start with working code - Always develop features in a concrete codebase first
  2. Use snapshots judiciously - Only for intentional differences, not generator bugs
  3. Validate frequently - Run diff commands often during development
  4. Test generated code - Ensure pnpm build && pnpm lint passes on synced code
  5. Keep commits focused - Separate generator changes from template changes when possible
  6. Document template variables - Use clear, descriptive names for template variables
  7. Sync all projects when done - Always run sync_all_projects to ensure all examples are updated