Skip to content

Instantly share code, notes, and snippets.

@jsquire
Last active July 9, 2025 22:59
Show Gist options
  • Save jsquire/7a7296c0f217db71cf56ad33feabbaa9 to your computer and use it in GitHub Desktop.
Save jsquire/7a7296c0f217db71cf56ad33feabbaa9 to your computer and use it in GitHub Desktop.
Azure SDK for .NET Code Generation Agent

Azure SDK for .NET Code Generation Agent

Executive summary

As the Azure SDK team’s role has evolved from authoring client libraries to building tools and processes that empower Azure service teams, delivering a polished, consistent developer experience has become increasingly important.

Today, code generation sits at the heart of our strategy, yet the current tooling presents significant challenges outside of the golden path. Specifically, there is a disconnect between TypeSpec—our abstract service contract definition—and the idiomatic .NET code we aim to produce. While the generator handles simple conversions automatically, more complex scenarios often lead to confusing failures that block key steps like generating an API View for architectural review.

To address this, we propose building an integrated set of tools that:

  • Automatically apply default fixes during generation, enabling partners to run the generator once and successfully produce an API View.

  • Detect and help resolve .NET-specific issues earlier, during TypeSpec authoring, through a linter and automated fixes.

  • Support local and CI workflows across command line, Visual Studio, and Visual Studio Code.

  • Provide a guided, interactive mode to reduce upfront configuration and improve usability.

This approach will enable Azure service teams to deliver high-quality .NET client libraries more efficiently and consistently, while reducing friction and dependence on deep architectural intervention.

Problem statement

As the Azure SDK team has evolved, we’ve shifted from primarily writing client libraries to building the processes and tools that empower our Azure service partners. Delivering polished, robust tools that help these teams succeed has become increasingly important.

Code generation is central to our strategy, but the current tooling offers a rough developer experience outside the golden path. A recurring challenge is the disconnect between TypeSpec—which models the service contract abstractly—and the generated .NET library code. Some names and concepts valid in the service definition, or in other client languages, are not idiomatic in .NET. While the generator handles straightforward, rule-based conversions automatically, more nuanced cases often require architectural review. Failures during this process can be overwhelming and difficult to resolve, and they block the creation of an API View, which is essential for architect discussions.

Goals

  1. Allow partners to run the generator once to achieve a successful outcome, automatically applying default fixes for .NET rule failures. At the end of the run, it should always be possible to produce an API View for architect discussions.

  2. Provide early detection of .NET rule failures during TypeSpec authoring, flagging issues and offering automatic fixes as TypeSpec is written. This enables partners to address problems early and avoids unexpected failures during generation.

  3. Support local use of the tooling via the command line, as an MCP tool usable in Visual Studio Code and Visual Studio, and integrated with the REST API specs repository flows.

  4. Ensure a consistent experience for generating both data plane and management Azure libraries.

Non-goals

  • Deep API analysis and adjustments that would obviate the need for archiect review. The adjustments made by the agent are intended to be good enough to comply with guidelines, but will still require architect review.

  • Providing an unbranded or generic experience. These tools are explicitly built for Azure scenarios and intended for use by Azure service teams developing client libraries.

  • Deep integration into the broader TypeSpec ecosystem. The tools are focused on the Azure code generation workflow and will integrate specifically with Azure engineering systems and tooling.

  • Supporting the legacy AutoRest generator. The tools will integrate only with the .NET TypeSpec generator (MTG).

Approach

  1. Build a generator agent that orchestrates the TypeSpec toolchain for .NET library generation. The agent will detect .NET rule failures and generator errors, and iteratively apply automatic fixes until generation succeeds or it can no longer make progress.

  2. Develop a Visual Studio Code extension to lint TypeSpec as it’s authored, detecting .NET rule failures and offering automatic fixes. This gives partners immediate feedback and helps prevent failures later in the generation process.

  3. Add an interactive mode to the generator agent that guides users through simple, step-by-step questions, reducing the need to configure the generator in advance.

  4. Expose an MCP interface so the generator agent can integrate with Visual Studio, Visual Studio Code, and the REST API specs pipeline.

  5. When run interactively, have the generator agent detect missing TypeSpec tooling in the environment and offer to install it automatically.

Things to know before reading

  • The names used in this document are intended for illustration only. Some names are not ideal and will need to be refined during discussions.

  • Some details not related to the core agent areas are not illustrated; the scope of this is limited to the high level shape and paradigms for the feature area.

  • Fake methods are used to illustrate "something needs to happen, but the details are unimportant." As a general rule, if an operation is not directly related to one of the core types, it can likely be assumed that it is for illustration only. These methods will most often use ellipses for the parameter list, in order to help differentiate them.

  • This document is focused on the .NET generator agent and shared infrastructure. The VS Code plugin for linting TypeSpec will be detailed by Arthur and team, who will be driving its design and development.

Assumptions and constraints

  • Azure partners using the generator agent have followed the Contributing Guide, forking the repository and ensuring that they have a basic .NET development environment available as a prerequisite.

  • All Azure partners belong to a common security group such that we can grant them access to interact with an Azure AI Fountry Agent as part of the generation process when running locally in non-MCP mode.

Usage examples

Installing the .NET generator agent

The generator agent will be packaged as a .NET tool and published to the Azure tools NuGet feed, following the same pattern as our snippet generator. This allows partners to install it using the standard dotnet CLI similar to:

> dotnet tool install -g Azure.Tools.GeneratorAgent

For more context, see: dotnet tool install and Create a .NET tool.

Generating with existing configuration

To generate an Azure library with an existing configuration, the tool invoked similar to the existing generator today:

> dotnet tool run generate ../my-service.tsp  --out-dir ./

 ====================================
| Azure SDK for .NET Generator Agent |
 ====================================
 
Compiling TypeSpec...      success!
Generating .NET library... success!
Building the library...    FAIL

  warning AZC0030: Model name 'DiskOptions' ends with 'Options'.   This makes Krzysztof sad 
  and he will not send you a holiday card.  Please rename 'DiskOptions' according to our guidleines 
  at https://bad.errormessage.contoso.com.
  
  warning AZC0030: Model name 'PersonOptions' ends with 'Options'.   This makes Krzysztof sad 
  and he will not send you a holiday card.  Please rename 'PersonOptions' according to our guidleines 
  at https://bad.errormessage.contoso.com.
  
  warning AZC0012: Single word class names are bad and you should feel bad.  Please rename `Fruit` to 
  a more suitable name according to our guidelines at https://bad.errormessage.contoso.com.

Attempting to fix AZC0030 failures.... success!
Attempting to fix AZC0012 failures.... success!

Compiling TypeSpec...      success!
Generating .NET library... success!
Building the library...    success! 

Your library was successfully generated in `/sdk/Contoso/Azure.ResourceManager.Contoso`

Generating interactively

To generate an Azure library, a TypeSpec configuration file must be available, containing the Azure context for the type of library that you'd like to emit. This can make getting started a burden, as partners need to understand what specific information is needed and how that is represented in configuration.

To improve this experience, the generator agent offers an interactive mode that provides a guided experience to gather information and create the needed configuration. This flow looks something like:

> dotnet tool run generate --interactive

 ====================================
| Azure SDK for .NET Generator Agent |
 ====================================
 
  Found TypeSpec file my-service.tsp in the current directory.
  If this is not the spec that you would like to generate, 
  where is the spec that should be used? (blank for ./my-service.tsp)
  
> 
(using ./my-service.tsp)
 
  Are you generating a:
  [1] Client library (data plane)
  [2] Management library  
  
> 2  
  
  What is the name of your service?  (example: Compute)
  
> Contoso

  Do you want to generate tests?
  [Y] Yes
  [N] No
  
> Y

  Do you want to generate samples?
  [Y] Yes
  [N] No
  
> Y

  Where should we write the configuration to?  (blank for the current directory)
  
> 
(using current directory)

Writing tspconfig.yaml...  success!

  Do you want to generate the library now?
  [Y] Yes
  [N] No
  
> Y

Compiling TypeSpec...      success!
Generating .NET library... success!
Building the library...    success!

Your library was successfully generated in `/sdk/Contoso/Azure.ResourceManager.Contoso`

Generating without the TypeSpec tooling installed

To generate an Azure library with an existing configuration, the tool invoked similar to the existing generator today:

> dotnet tool run generate ../my-service.tsp  --out-dir ./

 ====================================
| Azure SDK for .NET Generator Agent |
 ====================================
 
The TypeSpec compiler and toolchain is not detected!  

  Would you like ti install it now? 
  [Y] Yes
  [N] No
 
> N

Without the TypeSpec compiler and toolchain, generation cannot continue.  To manually install,
please see: https://typespec.io/docs/

Generating as an MCP tool

<< TBD >>

Lots of unknowns here still. Will be fleshed out later.

Technical Design Considerations

Product dependencies and ownership

At a high level, the generator agent and linter will be independent products with no dependency on each other. They will share a set of "error analyzers" so that each has a consistent approach to detecting .NET rule failures as well as general errors. Analyzers will be organized by the category of rule/error they recognize, both for organization and to support concurrent development and ownership by different teams.

Arthur's team will own the linter and the management analyzers. Our team will own the remainder.

graph TD
    A[Azure.Tools.GeneratorAgent]
    B[Azure.Tools.TypeSpecLinter]

    subgraph Shared_Analyzers["Shared Analyzers"]
        C[ClientRuleAnalyzers]
        D[ManagementRuleAnalyzers]
        E[GeneralErrorAnalyzers]
    end

    A --> C
    A --> D
    A --> E

    B --> C
    B --> D
    B --> E
Loading

Project hierarchy

Source code will be maintained in the Azure SDK Tools repository, alongside our other internally-focused Azure tooling. To support independent ownership, each component will have its own containing directory so that CODEOWNERS accurately reflects the areas of responsibility.

Azure SDK Tools Repository
/
└── src/dotnet
     ├── GeneratorAgent
     │   ├── src
     │   │   └── Azure.Tools.GeneratorAgent
     │   └── tests
     │       └── Azure.Tools.GeneratorAgent.Tests
     │
     ├── TypeSpecLinter
     │   ├── src
     │   │   └── Azure.Tools.TypeSpecLinter
     │   └── tests
     │       └── Azure.Tools.TypeSpecLinter.Tests
     │
     └── ErrorAnalyzers
         ├── Client
         │   ├── src
         │   │   └── Azure.Tools.GeneratorAgent.ClientRuleAnalyzers
         │   └── tests
         │       └── Azure.Tools.GeneratorAgent.ClientRuleAnalyzers.Tests
         │
         ├── General
         │   ├── src
         │   │   └── Azure.Tools.GeneratorAgent.GeneralErrorAnalyzers
         │   └── tests
         │       └── Azure.Tools.GeneratorAgent.GeneralErrorAnalyzers.Tests
         │
         └── Management
             ├── src
             │   └── Azure.Tools.GeneratorAgent.ManagementRuleAnalyzers
             └── tests
                 └── Azure.Tools.GeneratorAgent.ManagementRuleAnalyzers.Tests
          

Rule Analyzers

The rule analyzers are intended to be granular - each will know about one specific rule or error type and how to fix it. The caller will query each analyzer to ask "can you handle this" and choose the first that responds in the positive. The analyzer will then return a set of actions and context.

A rough outline of the initial contract for an analyzer would look something like the following. Note that As we analyze more concrete scenarios and plan for addressing real-world errors, these are expected change form.

public abstract class AgentRuleAnalyzer
{   
    // Example Error Tyoe: "ACX003"
    // Example Eeror Type: "InvalidOperationException"
    public abstract bool CanFix(string errorType);
    
    // Example Error: warning AZC0030: Model name 'DiskOptions' ends with 'Options'... (SNIP)
    // Example Error: TypesMustExist: Type 'Azure.Thing' does not exist in the implementation... (SNIP)
    public abstract IList<string> GetFixes(string error);
}

public class Fix
{
    public FixAction Action { get; }
    
    // Example: "In client.tsp, rename Foo to Bar using the dectorator"
    public string Action { get; }
    
    // OPTIONAL; Only used in some scenarios.  Provides scenario-specific
    // additional context.
    public string? Context { get; }
}

public enum FixAction
{
  AgentPrompt,
  Rename,
}

public class RuleError
{
    public string Type { get; }
    public string Message { get; }
}

The agent would use the analyzers similar to:

/// Dummy call to illustrate parsing generator output
// to extract analyzer rule errors.
List<string> errors = ParseRuleErrors(generatorOutput);

/// Dummy call to illustrate getting the set of analyzers
// which are known.
List<AgentRuleAnalyzer> ruleAnalyzers = GetRuleAnalyzers()

// Analyze errors and generate the fixes.
List<Fix> fixes = new();

foreach (var error in errors)
{
    foreach (var ruleAnalyzer in ruleAnalyzers)
    {
        if (ruleAnalyzer.CanFix(error.Type)
        {
            // We only care about the first analyzer that can fix
            // the error.  Break when we find one.
            fixes.AddRange(ruleAnalyzer.GetFixes(error.Message));
            break;
        }
    }
}

// Apply the fixes.
foreach (var fix in fixes)
{
   switch fix.Action
   {
       // Use the agent to make the fix.
       case FixAction.AgentPrompt:
         ApplyFixWithAgentPrompt(fix.Action);
         break;
         
       // This is a simple rename, we just need the "from" and "to" to apply.
       case FixAction.Rename:
         ApplyRename(from: fix.Context, to: fix.Action);
         break;
       
       default:
           Logger.Log($"I have no idea how to do {fix.Action}.  Skipping.");
           break;
   }
}

.NET Rules for Agent Automation

The following are the set of .NET rules that should be included in the initial set of rule analyzers and be candidates to be fixed automatically.

Client rules

Rule Code Analyzer Scenario Error Message
AZC0012 TypeNameAnalyzer Single word type names "Type name '{0}' is too generic and has high chance of collision with BCL types or types from other libraries. Consider using a more descriptive multi-word name, such as '{1}'."
AZC0030 GeneralSuffixAnalyzer Model naming suffix issues "Model name '{0}' ends with '{1}'. We suggest renaming it to '{2}' or another name with this suffix."
AZC0034 DuplicateTypeNameAnalyzer Type name conflicts "Type name '{0}' conflicts with '{1}'. Consider renaming to '{2}' to avoid confusion."
AZC0035 ModelFactoryAnalyzer Missing model factory methods "Output model type '{0}' should have a corresponding method in a model factory class. Add a static method that returns '{0}' to a class ending with 'ModelFactory'."

Management rules

Rule Code Analyzer Scenario Error Message
AZC0031 DefinitionSuffixAnalyzer Definition suffix naming in ResourceManager context "Model name '{0}' ends with '{1}'. Suggest to rename it to '{2}' or any other appropriate name."
AZC0032 DataSuffixAnalyzer Data suffix naming in ResourceManager context "Model name '{0}' ends with '{1}'. Suggest to rename it to '{2}' or any other appropriate name."
AZC0033 OperationSuffixAnalyzer Operation suffix naming in ResourceManager context "Model name '{0}' ends with '{1}'. We suggest renaming it to '{2}' or another name with these suffixes."
AZC0036 OptionsSuffixAnalyzer Options suffix in ResourceManager context "Model name '{0}' ends with '{1}'. The '{1}' suffix is reserved for input models described by https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-parameters. Please rename '{0}' to '{2}' or another suitable name according to our guidelines at https://azure.github.io/azure-sdk/general_design.html#model-types for output or roundtrip models."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment