🧠 Legacy Modernization Agents to migrate COBOL to Java developed with the Semantic Kernel Process Function
This migration framework was developed to demonstrate AI Agents capabilities for converting legacy code like COBOL to Java. Each Agent has a persona that can be edited depending on the desired outcome. The migration is using Semantic Kernel Process Function where it does analysis of the COBOL code and it’s dependencies. This information then used to converting Java Quarkus.
This project is a collaboration between Microsoft's Global Black Belt team and Bankdata. If you want to learn more about the collaboration and background of this project, have a look at this and this blog post.
We are looking for real COBOL code to further improve this framework. If you want to actively collaborate, please reach out to us by opening an issue in this repository. - Gustav Kaleta & Julia Kordick
Have a look at the talk Julia did at the WeAreDevelopers World Congress 2025: https://www.youtube.com/watch?v=62OI_y-KRlw
- Quick Start
- How It Works - Complete Architecture & Flow
- Known issues
- Project ideas
- Disclaimer
- Summary
- .NET 8.0.x
- Semantic Kernel SDK
- Azure OpenAI account with GPT-4.1 model deployed
- GPT-4.1 supports up to 1M Token per minute which you need edit in https://oai.azure.com/
INFO: Remember to read the entire repo to grasp of the project and how you can utilize it for your code base.
This project includes a dev container configuration for Visual Studio Code, which ensures a consistent development environment for all contributors.
Note on Java Version: The project uses Java 17 in the dev container because it's the latest version available in the standard Debian Bookworm repositories. Our dev container is based on
mcr.microsoft.com/devcontainers/dotnet:8.0, which uses Debian Bookworm as its base image.
- Docker installed on your machine
- Visual Studio Code with the "Dev Containers" extension installed
- Clone this repository
- Open the project folder in Visual Studio Code
- When prompted, click "Reopen in Container", or run the "Dev Containers: Reopen in Container" command from the command palette
- Wait for the container to build and initialize (this may take a few minutes the first time)
- The container includes all required dependencies:
- .NET 8.0
- Java 17 with Maven
- Azure CLI
- Required VS Code extensions
After the container is built, the project will be automatically restored and built.
The project uses a secure two-file configuration system:
Config/ai-config.env- Template with default values (✅ safe to commit)Config/ai-config.local.env- Your actual credentials (❌ never commit)
Setup your credentials:
# 1. Copy the template to create your local config
cp Config/ai-config.local.env.example Config/ai-config.local.env
# 2. Edit your local config with real values
nano Config/ai-config.local.envIn Config/ai-config.local.env, update these lines:
# Replace with your actual Azure OpenAI endpoint
AZURE_OPENAI_ENDPOINT="https://YOUR-RESOURCE-NAME.openai.azure.com/"
# Replace with your actual API key
AZURE_OPENAI_API_KEY="your-32-character-api-key-here"
# Update deployment name to match your Azure setup
AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4.1"🔍 How to find your Azure OpenAI values:
- Endpoint: Azure Portal → Your OpenAI Resource → "Resource Management" → "Keys and Endpoint" → Endpoint
- API Key: Azure Portal → Your OpenAI Resource → "Resource Management" → "Keys and Endpoint" → Key 1
- Deployment Name: Azure AI Foundry → Your deployment name (must be "gpt-4.1")
📋 Example ai-config.local.env with real values:
# Example - replace with your actual values
AZURE_OPENAI_ENDPOINT="https://my-company-openai.openai.azure.com/"
AZURE_OPENAI_API_KEY="1234567890abcdef1234567890abcdef"
AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4.1"
AZURE_OPENAI_MODEL_ID="gpt-4.1"- Make sure your endpoint ends with
/ - API key should be 32 characters long
- Deployment name must be exactly "gpt-4.1" to match project configuration
# 1. Validate your configuration
./doctor.sh doctor
# 2. Test configuration
./doctor.sh test
# 3. Add your COBOL files to cobol-source/ (or use the included samples)
cp your-cobol-files/* ./cobol-source/
# 4. Run migration
./doctor.sh runIf you see configuration errors:
# Check what's configured
./doctor.sh doctor
# Run interactive setup (guided process)
./doctor.sh setup
# Common issues:
# ❌ "test-api-key-for-validation" → You need to set real API key
# ❌ "test-resource.openai.azure.com" → You need to set real endpoint
# ❌ Model not found → Check your deployment name matches AzureThe doctor.sh script consolidates all functionality:
./doctor.sh setup- Interactive configuration./doctor.sh test- System validation./doctor.sh run- Start migration./doctor.sh doctor- Diagnose issues./doctor.sh resume- Resume interrupted migration./doctor.sh help- Show all commands
The Semantic Kernel process function is used to build an AI-powered COBOL-to-Java migration system that uses Microsoft Semantic Kernel framework to orchestrate multiple specialized AI agents. Here's how it works:
sequenceDiagram
participant User as 👤 User
participant CLI as 🖥️ CLI Program
participant Process as 🎯 MigrationProcess
participant Agents as 🤖 AI Agents
participant AI as 🧠 Azure OpenAI
participant Files as 📁 FileHelper
participant Logs as 📊 Loggers
User->>CLI: ./doctor.sh run or dotnet run
CLI->>CLI: Parse command line args
CLI->>Process: Initialize with settings
Note over Process: Step 1: File Discovery
Process->>Files: Scan COBOL directory
Files-->>Process: List of .cbl and .cpy files
Process->>Logs: Log file discovery stats
Note over Process: Step 2: Dependency Analysis
Process->>Agents: DependencyMapperAgent.AnalyzeDependenciesAsync()
Agents->>AI: Analyze COBOL relationships
AI-->>Agents: Dependency insights
Agents-->>Process: DependencyMap with Mermaid diagram
Process->>Files: Save dependency-map.json
Note over Process: Step 3: COBOL Analysis
loop For each COBOL file
Process->>Agents: CobolAnalyzerAgent.AnalyzeCobolFileAsync()
Agents->>AI: Analyze COBOL structure
AI-->>Agents: Structured analysis
Agents-->>Process: CobolAnalysis object
Process->>Logs: Log analysis progress
end
Note over Process: Step 4: Java Conversion
loop For each analyzed file
Process->>Agents: JavaConverterAgent.ConvertToJavaAsync()
Agents->>AI: Convert COBOL to Java Quarkus
AI-->>Agents: Java code
Agents-->>Process: JavaFile object
Process->>Logs: Log conversion progress
end
Note over Process: Step 5: File Generation
loop For each Java file
Process->>Files: Save Java file to output directory
Files-->>Process: Confirmation
Process->>Logs: Log file save progress
end
Note over Process: Step 6: Report Generation
Process->>Files: Generate migration-report.md
Process->>Logs: Export conversation logs
Process->>Logs: Show API statistics
Process-->>CLI: Migration complete
CLI-->>User: Success message + metrics
graph TB
subgraph SK_KERNEL ["🧠 Semantic Kernel Framework"]
direction TB
KERNEL["🔧 Kernel Builder<br/>• Chat Completion Services<br/>• Service Configuration<br/>• API Connection Management"]
PROMPT_ENGINE["📝 Prompt Engineering<br/>• System Prompts<br/>• User Prompts<br/>• Context Management"]
EXECUTION["⚙️ Execution Settings<br/>• Token Limits (32K)<br/>• Temperature (0.1)<br/>• Model Selection"]
end
subgraph AGENT_LIFECYCLE ["🔄 Agent Lifecycle Process"]
direction TB
INIT["1️⃣ Initialize Agent<br/>• Load Model Configuration<br/>• Set Specialized Prompts<br/>• Configure Logging"]
PROMPT["2️⃣ Create Task Prompt<br/>• Build System Context<br/>• Add COBOL Content<br/>• Define Output Format"]
EXECUTE["3️⃣ Execute via Kernel<br/>• Send to AI Service<br/>• Monitor API Call<br/>• Handle Timeouts"]
PROCESS_RESPONSE["4️⃣ Process Response<br/>• Parse AI Output<br/>• Validate Results<br/>• Extract Structured Data"]
LOG["5️⃣ Log & Track<br/>• Record API Metrics<br/>• Track Performance<br/>• Store Conversation"]
INIT --> PROMPT
PROMPT --> EXECUTE
EXECUTE --> PROCESS_RESPONSE
PROCESS_RESPONSE --> LOG
end
subgraph AI_MODELS ["🤖 AI Model Specialization"]
direction TB
ANALYZER_MODEL["🔍 COBOL Analyzer<br/>• Structure Analysis<br/>• Variable Mapping<br/>• Logic Flow Analysis<br/>• Copybook Detection"]
CONVERTER_MODEL["☕ Java Converter<br/>• Code Translation<br/>• Quarkus Integration<br/>• Best Practices<br/>• Error Handling"]
DEPENDENCY_MODEL["🗺️ Dependency Mapper<br/>• Relationship Analysis<br/>• Mermaid Diagrams<br/>• Usage Patterns<br/>• Metrics Calculation"]
end
%% Connections
SK_KERNEL --> AGENT_LIFECYCLE
AGENT_LIFECYCLE --> AI_MODELS
%% Enhanced Styling
classDef kernelStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:3px,color:#0d47a1
classDef lifecycleStyle fill:#f1f8e9,stroke:#689f38,stroke-width:3px,color:#1b5e20
classDef modelStyle fill:#fff3e0,stroke:#f57c00,stroke-width:3px,color:#e65100
classDef stepStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#4a148c
class KERNEL,PROMPT_ENGINE,EXECUTION kernelStyle
class INIT,PROMPT,EXECUTE,PROCESS_RESPONSE,LOG stepStyle
class ANALYZER_MODEL,CONVERTER_MODEL,DEPENDENCY_MODEL modelStyle
- Purpose: Command-line interface and configuration setup
- Key Functions:
- Parses command-line arguments (
--cobol-source,--java-output,--config) - Loads application settings from JSON configuration
- Initializes Semantic Kernel with Azure OpenAI or OpenAI
- Sets up HTTP client with extended timeouts for large files
- Creates and configures the main MigrationProcess
- Parses command-line arguments (
- Purpose: Main workflow orchestrator that coordinates all migration steps
- Key Responsibilities:
- Agent Initialization: Creates and configures all AI agents
- File Discovery: Scans directories for COBOL files (.cbl) and copybooks (.cpy)
- Dependency Analysis: Maps relationships between COBOL programs
- COBOL Analysis: Analyzes each file's structure and logic
- Java Conversion: Converts COBOL to Java Quarkus code
- File Generation: Saves all generated Java files
- Report Creation: Generates comprehensive migration reports
- Purpose: Expert in COBOL code analysis
- AI Prompt: Specialized system prompt for understanding COBOL structure
- Output: Structured analysis including:
- Data divisions and variables
- Procedure divisions and paragraphs
- Logic flow and control structures
- Copybook references
- Purpose: Expert in COBOL-to-Java conversion
- AI Prompt: Specialized for Java Quarkus code generation
- Output: Complete Java classes with:
- Proper class structures
- Modern Java data types
- Quarkus framework integration
- Error handling and best practices
- Purpose: Expert in dependency analysis and visualization
- Capabilities:
- Analyzes COBOL program relationships
- Identifies copybook usage patterns
- Generates Mermaid dependency diagrams
- Calculates dependency metrics
- Purpose: Handles all file operations
- Functions:
- Scanning directories for COBOL files
- Reading and writing files
- Creating output directory structures
- Saving JSON and Markdown reports
- Purpose: Advanced logging with API call tracking
- Features:
- Behind-the-scenes activity logging
- API call performance metrics
- Progress bars and status updates
- Cost analysis and token tracking
- Purpose: Records AI conversations
- Output:
- Complete chat logs in Markdown format
- JSON conversation exports
- Statistics on messages and tokens
{
"AISettings": {
"ServiceType": "AzureOpenAI",
"Endpoint": "https://your-resource.openai.azure.com/",
"ApiKey": "your-api-key",
"DeploymentName": "gpt-4.1",
"ModelId": "gpt-4.1",
"CobolAnalyzerModelId": "gpt-4.1",
"JavaConverterModelId": "gpt-4.1",
"DependencyMapperModelId": "gpt-4.1"
},
"ApplicationSettings": {
"CobolSourceFolder": "cobol-source",
"JavaOutputFolder": "java-output"
}
}- 📁 Source Files: 102 COBOL files processed
- ☕ Generated Files: 99 Java files created
- 🔗 Dependencies: Complex relationship mapping
- ⏱️ Processing Time: ~1.2 hours for full migration
- 💰 AI Cost: $0.31 for complete migration
- 📞 API Calls: 205 calls to Azure OpenAI
- 🎯 Success Rate: 97% successful conversion
-
Java Packages: Organized by functionality
com.example.*- Business logic (85 files)org.example.*- Batch processors (5 files)com.company.*- Domain-specific logic (2 files)com.enterprise.*- Enterprise services (2 files)model.*- Data models (2 files)
-
Documentation:
dependency-map.json- Complete dependency analysisdependency-diagram.md- Mermaid visualizationmigration-report.md- Comprehensive migration summarymigration-conversation-log.md- AI agent conversations
-
Logs Directory:
- API call tracking logs
- Processing step logs
- Error and warning logs
- Performance metrics
- 🧠 AI Orchestration: Seamlessly manages multiple AI models and prompts
- 🔄 Workflow Management: Handles complex multi-step processes
- 📊 Observability: Complete tracking of AI interactions and performance
- 🎚️ Configurability: Easy switching between AI providers and models
- 🧪 Extensibility: Simple to add new agents and capabilities
- 🛡️ Error Handling: Robust error handling and recovery mechanisms
- 📈 Scalability: Efficient processing of large COBOL codebases
This Semantic Kernel-based architecture transforms the complex task of COBOL-to-Java migration into a manageable, observable, and highly effective automated process! 🚀
// Initialize kernel builder
var kernelBuilder = Kernel.CreateBuilder();
if (settings.AISettings.ServiceType.Equals("OpenAI", StringComparison.OrdinalIgnoreCase))
{
kernelBuilder.AddOpenAIChatCompletion(
modelId: settings.AISettings.ModelId,
apiKey: settings.AISettings.ApiKey);
}
else if (settings.AISettings.ServiceType.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase))
{
kernelBuilder.AddAzureOpenAIChatCompletion(
deploymentName: settings.AISettings.DeploymentName,
endpoint: settings.AISettings.Endpoint,
apiKey: settings.AISettings.ApiKey,
httpClient: httpClient);
}
// Pass kernel builder to migration process
var migrationProcess = new MigrationProcess(kernelBuilder, logger, fileHelper, settings);What this does:
- Creates the Semantic Kernel foundation that all agents will use
- Configures AI service connection (Azure OpenAI or OpenAI)
- Sets up HTTP client with extended timeouts for large COBOL files
- Passes kernel builder to the migration orchestrator
public void InitializeAgents()
{
// Each agent gets the kernel builder to create their own kernel instances
_cobolAnalyzerAgent = new CobolAnalyzerAgent(
_kernelBuilder, // ← Semantic Kernel builder passed here
logger,
_settings.AISettings.CobolAnalyzerModelId,
_enhancedLogger,
_chatLogger);
_javaConverterAgent = new JavaConverterAgent(
_kernelBuilder, // ← Semantic Kernel builder passed here
logger,
_settings.AISettings.JavaConverterModelId,
_enhancedLogger,
_chatLogger);
_dependencyMapperAgent = new DependencyMapperAgent(
_kernelBuilder, // ← Semantic Kernel builder passed here
logger,
_settings.AISettings.DependencyMapperModelId,
_enhancedLogger,
_chatLogger);
}What this does:
- Distributes the kernel builder to each specialized AI agent
- Enables each agent to create their own kernel instances
- Maintains consistency in AI service configuration across agents
public async Task<CobolAnalysis> AnalyzeCobolFileAsync(CobolFile cobolFile)
{
// Build kernel instance from the builder
var kernel = _kernelBuilder.Build(); // ← Creates Semantic Kernel instance
// Create specialized prompts for COBOL analysis
var systemPrompt = "You are an expert COBOL analyzer...";
var prompt = $"Analyze the following COBOL program:\n\n{cobolFile.Content}";
var fullPrompt = $"{systemPrompt}\n\n{prompt}";
// Configure execution settings
var executionSettings = new OpenAIPromptExecutionSettings
{
MaxTokens = 32768,
Temperature = 0.1,
TopP = 0.5
};
var kernelArguments = new KernelArguments(executionSettings);
// Execute AI call through Semantic Kernel
var functionResult = await kernel.InvokePromptAsync( // ← SK process function call
fullPrompt,
kernelArguments);
var analysisText = functionResult.GetValue<string>();
// Parse response into structured CobolAnalysis object
}What this does:
- Creates kernel instance from the shared builder
- Uses specialized COBOL analysis prompts
- Configures AI parameters (tokens, temperature)
- Executes AI call through
kernel.InvokePromptAsync()- this is the core SK process function - Returns structured analysis of COBOL code
public async Task<JavaFile> ConvertToJavaAsync(CobolFile cobolFile, CobolAnalysis analysis)
{
// Build kernel instance
var kernel = _kernelBuilder.Build(); // ← Creates SK instance
// Create Java conversion prompts
var systemPrompt = "You are an expert in converting COBOL to Java Quarkus...";
var prompt = $"Convert the following COBOL program to Java:\n\n{cobolFile.Content}";
// Execute conversion through Semantic Kernel
var functionResult = await kernel.InvokePromptAsync( // ← SK process function call
fullPrompt,
kernelArguments);
var javaCode = functionResult.GetValue<string>();
// Parse and structure Java output
}What this does:
- Uses same kernel builder but with Java conversion expertise
- Applies specialized Java/Quarkus prompts
- Executes conversion through
kernel.InvokePromptAsync()- core SK process function - Returns structured Java file with proper class definitions
public async Task<DependencyMap> AnalyzeDependenciesAsync(List<CobolFile> files, List<CobolAnalysis> analyses)
{
// Build kernel for dependency analysis
var kernel = _kernelBuilder.Build(); // ← Creates SK instance
// Create dependency analysis prompts
var systemPrompt = "You are an expert in analyzing COBOL dependencies...";
// Execute dependency analysis through Semantic Kernel
var functionResult = await kernel.InvokePromptAsync( // ← SK process function call
fullPrompt,
kernelArguments);
// Parse dependency relationships and generate Mermaid diagrams
}
private async Task<string> GenerateMermaidDiagramAsync(DependencyMap dependencyMap)
{
// Build kernel for diagram generation
var kernel = _kernelBuilder.Build(); // ← Creates SK instance
// Execute Mermaid generation through Semantic Kernel
var functionResult = await kernel.InvokePromptAsync( // ← SK process function call
diagramPrompt,
kernelArguments);
return functionResult.GetValue<string>();
}What this does:
- Analyzes program relationships using AI through SK
- Generates Mermaid diagrams using AI through SK
- Maps copybook usage and dependencies
- Calculates metrics on dependency complexity
kernel.InvokePromptAsync(prompt, kernelArguments)- Used in: All 3 AI agents for every AI call
- Purpose: Execute AI prompts through configured AI service
- Parameters:
prompt- The system + user promptkernelArguments- Execution settings (tokens, temperature, etc.)
var kernel = _kernelBuilder.Build()- Used in: Each agent method that needs AI
- Purpose: Create kernel instance from shared configuration
- Result: Ready-to-use kernel with AI service connection
kernelBuilder.AddAzureOpenAIChatCompletion(...)
kernelBuilder.AddOpenAIChatCompletion(...)- Used in: Program.cs initialization
- Purpose: Configure AI service connection
- Result: Kernel builder ready for agent distribution
graph LR
A[Program.cs<br/>Create KernelBuilder] --> B[MigrationProcess.cs<br/>Distribute to Agents]
B --> C[Agent.Build Kernel]
C --> D[kernel.InvokePromptAsync]
D --> E[AI Service Call]
E --> F[Structured Response]
style A fill:#e3f2fd
style D fill:#f1f8e9
style E fill:#fff3e0
- The project will create a Java-output folder will create a migration report with a summary of the generated files, dependencies analysis, metrics etc.
- The Logs folder will have analysis, apiCalls ConversionsOutput and a full chat log of the conversion as markdown.
- Depending on the Cobol file size you can always adjust the tokensize. GPT-4.1 has a limit for approx 32768 tokens, hence this specific setting. Ajust these accordingly for each agent.
- You can try different models, just remember to change the settings in the projects.
- If you want to change the agents output, you can change their persona and their tasks.
- If you for example do not want to convert code to Java you can change it to only do .NET
- If you for example only want to create documentation you can change the Java agent persona or create a new agent.
- If you want it to focus on specific areas or ouput you change or add those into the agents persona directly.
- For example it needs to focus on DB2 migration to PostgreSQL
- For example you want to reflect the SQL queries in a desired way add those to the agent's.
- For example if you want the Java folder struckture to reflect Maven so it you can easily build your project
- For example you want to the output to be .NET focused in instead - change that Java Agent for this specifically
- (Experimental) For example you have another legacy code language you can use the same approach like with APL
- Replace cobol code with APL and remember to update the agents to focus on APL and not Cobol
- Update the Java agent or create a new agent to reflect the desired programming language output
Please dicuss what the desires AI agents persona in order to reflect your desired outcome
Will be updated as we go.
- Content filtering can stop calls to Azure OpenAI.
- Make sure you do not increase your tokensize above the agents setting as it't already at it hightest limit.
- tbd
- feel free to contribute with ideas and improvements
This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The creators of this software make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the software or the information, products, services, or related graphics contained in the software for any purpose. Any reliance you place on such information is therefore strictly at your own risk.
Summary: The Semantic Kernel process functions are the core engine that powers every AI interaction in the migration tool, providing a consistent, observable, and manageable way to orchestrate complex AI workflows across multiple specialized agents! 🚀
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE