# Cadenza + Microsoft Agent Framework + Microsoft Foundry

> Source: <https://gist.github.com/rkttu/38c23d0f9faa7f5e38e6cb8d4ae61356>
> Published: 2026-06-18 14:50:47+00:00

다음과 같이 바이브코딩 프롬프트를 입력하면 쉽게 Cadenza 기반 코드를 빠르게 시작할 수 있습니다. 그 후, dotnet run 명령어나 chmod +x file.cs 명령어로 실행 권한을 부여한 다음 실행하면 손쉽게 실행할 수 있습니다.

```
먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:
먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

https://www.naver.com 사이트를 1초 간격으로 5회 https로 ping 하는 코드를 만들어줘.
먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

간단한 사칙 연산 계산기를 OpenAPI 형식으로 기능을 구현하고 프론트엔드 HTML 페이지를 담는 웹 사이트를 만들었으면 해.
먼저 https://raw.githubusercontent.com/rkttu/cadenza/main/README.ko.md 를 읽고, 거기 적힌 Cadenza 규칙(단일 .cs, shebang + #:sdk 지시문, 정확한 버전 핀, Console 대신 ambient helper)을 그대로 지켜 .NET 10 파일 기반 앱으로 다음을 구현하고 dotnet run으로 실행해줘:

콘솔 형태로 사용할 수 있는 AI 에이전트를 만들려고 해. OPENAPI_ENDPOINT, OPENAPI_MODEL, OPENAPI_KEY 라는 환경 변수를 미리 설정해두었고, 임의의 난수를 생성해서 반환하는 도구를 하나 내장한 에이전트를 만들려고 해.
```

| #!/usr/bin/env dotnet run | |
| #:sdk Cadenza@1.0.15 | |
| #:package Azure.AI.Projects@2.0.1 | |
| #:package Microsoft.Agents.AI@1.10.0 | |
| #:package Microsoft.Agents.AI.Foundry@1.5.0 | |
| #:package Azure.Identity@1.21.0 | |
| using Azure.AI.Projects; | |
| using Azure.Identity; | |
| using Microsoft.Extensions.AI; | |
| // Last successful run context: | |
| // - FOUNDRY_PROJECT_ENDPOINT | |
| // - FOUNDRY_MODEL_DEPLOYMENT | |
| // - AZURE_TENANT_ID | |
| // - PATH included Azure CLI dir: C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin | |
| // Installed software used: | |
| // - Microsoft Azure CLI (az.cmd) at C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\az.cmd | |
| var endpoint = Env.Get("FOUNDRY_PROJECT_ENDPOINT") | |
| ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is required."); | |
| var modelDeployment = Env.Get("FOUNDRY_MODEL_DEPLOYMENT") | |
| ?? throw new InvalidOperationException("FOUNDRY_MODEL_DEPLOYMENT environment variable is required."); | |
| var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential()); | |
| var tools = new List<AITool> | |
| { | |
| (AITool)AIFunctionFactory.Create( | |
| (Func<string>)(() => DateTimeOffset.Now.ToString("O")), | |
| name: "get_current_time", | |
| description: "Returns the current local time in ISO-8601 format.", | |
| serializerOptions: null) | |
| }; | |
| var agent = projectClient.AsAIAgent( | |
| model: modelDeployment, | |
| instructions: "You are a concise assistant. If the user asks for the current time, call get_current_time.", | |
| name: "cadenza-file-agent-console", | |
| description: "Single-file agent with a sample time tool and console chat.", | |
| tools: tools); | |
| // Keep local transcript so each turn includes prior context. | |
| var history = new List<ChatMessage>(); | |
| WriteLine("Console chat started. Type '/exit' to quit."); | |
| while (true) | |
| { | |
| Write("you> "); | |
| var userInput = Console.ReadLine(); | |
| if (string.IsNullOrWhiteSpace(userInput)) | |
| { | |
| continue; | |
| } | |
| if (string.Equals(userInput.Trim(), "/exit", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| WriteLine("bye."); | |
| break; | |
| } | |
| history.Add(new ChatMessage(ChatRole.User, userInput)); | |
| var runResult = await agent.RunAsync(history, session: null, options: null, cancellationToken: default); | |
| // AgentResponse concrete shape may evolve; reflect common output fields safely. | |
| var resultType = runResult.GetType(); | |
| var text = resultType.GetProperty("Text")?.GetValue(runResult)?.ToString(); | |
| var answer = text ?? runResult.ToString() ?? string.Empty; | |
| WriteLine($"agent> {answer}"); | |
| history.Add(new ChatMessage(ChatRole.Assistant, answer)); | |
| } |

| #!/usr/bin/env dotnet run | |
| #:sdk Cadenza@1.0.15 | |
| #:package Azure.AI.Projects@2.0.1 | |
| #:package Microsoft.Agents.AI@1.10.0 | |
| #:package Microsoft.Agents.AI.Foundry@1.5.0 | |
| #:package Azure.Identity@1.21.0 | |
| // Last successful run context: | |
| // - FOUNDRY_PROJECT_ENDPOINT | |
| // - FOUNDRY_MODEL_DEPLOYMENT | |
| // - AZURE_TENANT_ID | |
| // - PATH included Azure CLI dir: C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin | |
| // Installed software used: | |
| // - Microsoft Azure CLI (az.cmd) at C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\az.cmd | |
| using Azure.AI.Projects; | |
| using Azure.Identity; | |
| var endpoint = Env.Get("FOUNDRY_PROJECT_ENDPOINT") | |
| ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is required."); | |
| var modelDeployment = Env.Get("FOUNDRY_MODEL_DEPLOYMENT") | |
| ?? throw new InvalidOperationException("FOUNDRY_MODEL_DEPLOYMENT environment variable is required."); | |
| var projectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential()); | |
| var agent = projectClient.AsAIAgent( | |
| model: modelDeployment, | |
| instructions: "You are a concise assistant. Respond in one sentence.", | |
| name: "cadenza-file-agent", | |
| description: "Single-file agent built with Cadenza + Microsoft Agent Framework + Foundry."); | |
| var prompt = "Say exactly 'Cadenza Foundry Agent is running.'"; | |
| var runResult = await agent.RunAsync(prompt, session: null, options: null, cancellationToken: default); | |
| // AgentResponse concrete shape may evolve; reflect common output fields safely. | |
| var resultType = runResult.GetType(); | |
| var text = resultType.GetProperty("Text")?.GetValue(runResult)?.ToString(); | |
| WriteLine($"Prompt: {prompt}"); | |
| WriteLine($"Response: {text ?? runResult.ToString()}"); |

| #!/usr/bin/env dotnet run | |
| #:sdk Cadenza.Agent@1.0.15 | |
| using System.ClientModel; | |
| using OpenAI; | |
| var endpoint = Env.Get("OPENAPI_ENDPOINT") | |
| ?? throw new InvalidOperationException("OPENAPI_ENDPOINT environment variable is required."); | |
| var model = Env.Get("OPENAPI_MODEL") | |
| ?? throw new InvalidOperationException("OPENAPI_MODEL environment variable is required."); | |
| var apiKey = Env.Get("OPENAPI_KEY") | |
| ?? throw new InvalidOperationException("OPENAPI_KEY environment variable is required."); | |
| SystemPrompt(""" | |
| You are a helpful console AI assistant. | |
| When users ask for randomness, prefer calling the `random_int` tool. | |
| Explain the generated random number briefly and clearly. | |
| """); | |
| Tool("random_int", "Generate a random integer between min and max (inclusive).", | |
| (int min, int max) => | |
| { | |
| if (min > max) | |
| return new { min, max, value = (int?)null, error = "min must be less than or equal to max." }; | |
| var value = Random.Shared.Next(min, max + 1); | |
| return new { min, max, value = (int?)value, error = (string?)null }; | |
| }); | |
| var options = new OpenAIClientOptions | |
| { | |
| Endpoint = new Uri(endpoint) | |
| }; | |
| var chatClient = new OpenAI.Chat.ChatClient(model, new ApiKeyCredential(apiKey), options) | |
| .AsIChatClient(); | |
| UseChatClient(chatClient); | |
| WriteLine("Console AI agent is ready."); | |
| WriteLine("- Backend endpoint: " + endpoint); | |
| WriteLine("- Model: " + model); | |
| WriteLine("- Tool: random_int(min, max)"); | |
| WriteLine(); | |
| WriteLine("Usage:"); | |
| WriteLine("- dotnet run .\\agent_console_random.cs"); | |
| WriteLine(" (interactive REPL)"); | |
| WriteLine("- dotnet run .\\agent_console_random.cs \"Generate a random number between 1 and 100\""); | |
| WriteLine(" (one-shot response)"); | |
| WriteLine(); | |
| if (args.Length > 0) | |
| { | |
| var prompt = string.Join(" ", args); | |
| var reply = await Reply(prompt); | |
| WriteLine(reply); | |
| return; | |
| } | |
| await ChatLoop(); |

| #!/usr/bin/env dotnet run | |
| #:sdk Cadenza.Web@1.0.15 | |
| using System.Globalization; | |
| using Microsoft.AspNetCore.Http; | |
| const string HtmlPage = """ | |
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>Cadenza Calculator</title> | |
| <style> | |
| :root { | |
| --bg: #f4f7ff; | |
| --panel: #ffffff; | |
| --ink: #1d2433; | |
| --muted: #5f697d; | |
| --accent: #0b7a57; | |
| --line: #d4ddef; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| min-height: 100vh; | |
| display: grid; | |
| place-items: center; | |
| padding: 20px; | |
| color: var(--ink); | |
| font-family: "Segoe UI", Tahoma, sans-serif; | |
| background: | |
| radial-gradient(circle at 10% 10%, #e9f0ff 0%, transparent 40%), | |
| radial-gradient(circle at 90% 90%, #def6ea 0%, transparent 35%), | |
| var(--bg); | |
| } | |
| main { | |
| width: min(760px, 100%); | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: 14px; | |
| box-shadow: 0 14px 30px rgba(16, 34, 74, 0.12); | |
| overflow: hidden; | |
| } | |
| header { | |
| padding: 18px 20px; | |
| border-bottom: 1px solid var(--line); | |
| background: linear-gradient(135deg, #f8fbff, #eefaf4); | |
| } | |
| h1 { margin: 0; font-size: 1.35rem; } | |
| p { margin: 8px 0 0; color: var(--muted); } | |
| .content { padding: 20px; display: grid; gap: 12px; } | |
| .row { display: grid; gap: 10px; grid-template-columns: 1fr 130px 1fr auto; } | |
| input, select, button { font: inherit; } | |
| input, select { | |
| width: 100%; | |
| border: 1px solid var(--line); | |
| border-radius: 10px; | |
| padding: 10px 12px; | |
| background: #fff; | |
| } | |
| button { | |
| border: 0; | |
| border-radius: 10px; | |
| padding: 10px 14px; | |
| background: var(--accent); | |
| color: #fff; | |
| font-weight: 600; | |
| cursor: pointer; | |
| } | |
| pre { | |
| margin: 0; | |
| min-height: 130px; | |
| border: 1px solid var(--line); | |
| border-radius: 10px; | |
| padding: 12px; | |
| background: #fff; | |
| overflow: auto; | |
| } | |
| .links { display: flex; gap: 12px; flex-wrap: wrap; } | |
| .links a { color: var(--accent); text-underline-offset: 3px; } | |
| @media (max-width: 640px) { .row { grid-template-columns: 1fr; } } | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <header> | |
| <h1>Arithmetic Calculator</h1> | |
| <p>Cadenza.Web single-file app with OpenAPI JSON endpoint.</p> | |
| </header> | |
| <section class="content"> | |
| <div class="row"> | |
| <input id="a" type="number" step="any" value="12" aria-label="a" /> | |
| <select id="op" aria-label="op"> | |
| <option value="add">add (+)</option> | |
| <option value="sub">sub (-)</option> | |
| <option value="mul">mul (*)</option> | |
| <option value="div">div (/)</option> | |
| </select> | |
| <input id="b" type="number" step="any" value="3" aria-label="b" /> | |
| <button id="run" type="button">Calculate</button> | |
| </div> | |
| <pre id="result">No calculation yet.</pre> | |
| <div class="links"> | |
| <a href="/openapi/v1.json" target="_blank" rel="noreferrer">OpenAPI JSON</a> | |
| <a href="/api/calc?a=12&b=3&op=div" target="_blank" rel="noreferrer">Sample API call</a> | |
| </div> | |
| </section> | |
| </main> | |
| <script> | |
| const resultEl = document.getElementById('result'); | |
| const runBtn = document.getElementById('run'); | |
| runBtn.addEventListener('click', async () => { | |
| const a = document.getElementById('a').value; | |
| const b = document.getElementById('b').value; | |
| const op = document.getElementById('op').value; | |
| const url = `/api/calc?a=${encodeURIComponent(a)}&b=${encodeURIComponent(b)}&op=${encodeURIComponent(op)}`; | |
| resultEl.textContent = 'Calculating...'; | |
| try { | |
| const response = await fetch(url); | |
| const data = await response.json(); | |
| resultEl.textContent = JSON.stringify(data, null, 2); | |
| } catch (err) { | |
| resultEl.textContent = String(err); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |
| """; | |
| const string OpenApiJson = """ | |
| { | |
| "openapi": "3.0.3", | |
| "info": { | |
| "title": "Cadenza Arithmetic Calculator API", | |
| "version": "1.0.0", | |
| "description": "Simple arithmetic operations: add, sub, mul, div" | |
| }, | |
| "servers": [ | |
| { "url": "http://localhost:8080" } | |
| ], | |
| "paths": { | |
| "/api/calc": { | |
| "get": { | |
| "summary": "Calculate with query parameters", | |
| "parameters": [ | |
| { "name": "a", "in": "query", "required": true, "schema": { "type": "number", "format": "double" } }, | |
| { "name": "b", "in": "query", "required": true, "schema": { "type": "number", "format": "double" } }, | |
| { "name": "op", "in": "query", "required": true, "schema": { "type": "string", "enum": ["add", "sub", "mul", "div"] } } | |
| ], | |
| "responses": { | |
| "200": { "description": "Calculation succeeded" }, | |
| "400": { "description": "Invalid input" } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| """; | |
| Get("/", () => Results.Content(HtmlPage, "text/html; charset=utf-8")); | |
| Get("/api/calc", (string a, string b, string op) => | |
| { | |
| if (!double.TryParse(a, NumberStyles.Float, CultureInfo.InvariantCulture, out var left)) | |
| return Results.BadRequest(new { error = "Parameter 'a' must be a valid number." }); | |
| if (!double.TryParse(b, NumberStyles.Float, CultureInfo.InvariantCulture, out var right)) | |
| return Results.BadRequest(new { error = "Parameter 'b' must be a valid number." }); | |
| var normalized = NormalizeOp(op); | |
| if (!TryCalculate(left, right, normalized, out var result, out var error)) | |
| return Results.BadRequest(new { error }); | |
| return Results.Ok(new | |
| { | |
| a = left, | |
| b = right, | |
| op = normalized, | |
| expression = $"{left} {OpSymbol(normalized)} {right}", | |
| result | |
| }); | |
| }); | |
| Get("/openapi/v1.json", () => Results.Content(OpenApiJson, "application/json; charset=utf-8")); | |
| await Run(); | |
| static bool TryCalculate(double a, double b, string op, out double value, out string error) | |
| { | |
| value = 0; | |
| error = string.Empty; | |
| switch (op) | |
| { | |
| case "add": | |
| value = a + b; | |
| return true; | |
| case "sub": | |
| value = a - b; | |
| return true; | |
| case "mul": | |
| value = a * b; | |
| return true; | |
| case "div": | |
| if (b == 0) | |
| { | |
| error = "Division by zero is not allowed."; | |
| return false; | |
| } | |
| value = a / b; | |
| return true; | |
| default: | |
| error = "Parameter 'op' must be one of: add, sub, mul, div."; | |
| return false; | |
| } | |
| } | |
| static string NormalizeOp(string? op) => | |
| (op ?? string.Empty).Trim().ToLowerInvariant() switch | |
| { | |
| "+" => "add", | |
| "-" => "sub", | |
| "*" => "mul", | |
| "/" => "div", | |
| var x => x, | |
| }; | |
| static string OpSymbol(string op) => op switch | |
| { | |
| "add" => "+", | |
| "sub" => "-", | |
| "mul" => "*", | |
| "div" => "/", | |
| _ => "?" | |
| }; |

| { | |
| "servers": { | |
| "brave-search": { | |
| "command": "npx", | |
| "args": [ | |
| "-y", | |
| "@brave/brave-search-mcp-server", | |
| "--transport", | |
| "stdio" | |
| ], | |
| "env": { | |
| "BRAVE_API_KEY": "${input:brave_api_key}" | |
| }, | |
| "type": "stdio" | |
| }, | |
| "handmirrormcp": { | |
| "type": "stdio", | |
| "command": "dnx", | |
| "args": ["HandMirrorMcp@0.1.1", "--yes"] | |
| }, | |
| "microsoft-learn": { | |
| "type": "http", | |
| "url": "https://learn.microsoft.com/api/mcp" | |
| } | |
| }, | |
| "inputs": [ | |
| { | |
| "id": "brave_api_key", | |
| "type": "promptString", | |
| "description": "Brave Search API Key" | |
| } | |
| ] | |
| } |

다음과 같이 바이브코딩 프롬프트를 입력하면 쉽게 Cadenza 기반 코드를 빠르게 시작할 수 있습니다. 그 후, dotnet run 명령어나 chmod +x file.cs 명령어로 실행 권한을 부여한 다음 실행하면 손쉽게 실행할 수 있습니다.

␃WPNCODE0␃

␃WPNCODE1␃

␃WPNCODE2␃

␃WPNCODE3␃
