<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Sajeetharan Sinnathurai | Developer Tooling, Azure Cosmos DB &amp; Coding Agents Blog</title>
        <link>https://www.sajeetharan.dev/blogs</link>
        <description>Sajeetharan Sinnathurai | Developer Tooling, Azure Cosmos DB &amp; Coding Agents Blog</description>
        <lastBuildDate>Sat, 03 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 Sajeetharan</copyright>
        <item>
            <title><![CDATA[Build an AI Agent with Azure Cosmos DB: End-to-End Guide]]></title>
            <link>https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db</link>
            <guid>https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db</guid>
            <pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Build a TypeScript AI agent with Azure Cosmos DB, React, durable memory, tenant isolation, diagnostics, tests, and a clear path from local development to Azure.]]></description>
            <content:encoded><![CDATA[
<p>Building an AI agent with Azure Cosmos DB is easy to demonstrate. Building the secure, observable, and deployable application around that agent is the difficult part.</p>
<p>A real customer-facing agent needs more than a prompt and a model endpoint. It needs durable memory, tenant isolation, authentication, citations, diagnostics, tests, deployment infrastructure, and a safe way to move from a local prototype to production.</p>
<p>I wanted to see how much of that work could be removed from the critical path, so I tried the <a href="https://github.com/sajeetharan/cosmos-agent-starter" target="_blank" rel="noopener noreferrer"><code>create-cosmos-agent</code></a> starter from beginning to end. I generated a customer-support agent, ran it against the Azure Cosmos DB Linux emulator, stored a customer preference, retrieved it through the chat experience, verified user isolation, inspected diagnostics, and ran the complete validation suite.</p>
<p>The result was a working full-stack application without an Azure subscription, model API key, or cloud resource.</p>
<p><img decoding="async" loading="lazy" alt="Build an AI agent with Azure Cosmos DB using React, TypeScript, durable memory, tenant isolation, and the local emulator" src="https://www.sajeetharan.dev/assets/images/build-ai-agent-cosmos-db-og-15674999fb7379bd0d27447742afc4fc.png" width="1200" height="630" class="img_ev3q"></p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Quick answer</div><div class="admonitionContent_BuS1"><p><code>create-cosmos-agent</code> generates a React and TypeScript agent application with memory, tenant isolation, citations, diagnostics, tests, and Azure infrastructure. The default local path needs no Azure subscription or model key; choose the Cosmos DB emulator when you want durable local data.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-create-cosmos-agent">What is <code>create-cosmos-agent</code>?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#what-is-create-cosmos-agent" class="hash-link" aria-label="Direct link to what-is-create-cosmos-agent" title="Direct link to what-is-create-cosmos-agent">​</a></h2>
<p><code>create-cosmos-agent</code> is a guided CLI for generating production-oriented TypeScript agent applications. Instead of creating only a chat screen, it scaffolds the surrounding application contracts:</p>
<ul>
<li>An Express API and React web application</li>
<li>Multiple AI provider adapters</li>
<li>In-memory or Azure Cosmos DB storage</li>
<li>Durable, scoped agent memory</li>
<li>Knowledge ingestion and vector retrieval</li>
<li>Customer-support workflows</li>
<li>Multi-agent orchestration</li>
<li>Approval-gated actions</li>
<li>Microsoft Entra ID authentication support</li>
<li>OpenTelemetry-style diagnostics</li>
<li>Unit, security, cost, and integration tests</li>
<li>Docker and Azure Developer CLI infrastructure</li>
</ul>
<p>The local and Azure paths use the same application interfaces. That is important: moving to production should be a configuration and infrastructure step, not a rewrite of the application.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Local development                         Azure production</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">-----------------                         ----------------</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Mock or Ollama --------.                  Microsoft Entra ID</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Memory or emulator ----+--&gt; Agent API --&gt; Managed Identity</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Local identity --------'         |        Azure Cosmos DB</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                +-------&gt; Azure OpenAI</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                +-------&gt; Application Insights</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                '-------&gt; Approval-gated actions</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-sample-i-built">The sample I built<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#the-sample-i-built" class="hash-link" aria-label="Direct link to The sample I built" title="Direct link to The sample I built">​</a></h2>
<p>For this walkthrough, I selected the <strong>customer-support</strong> scenario with:</p>
<ul>
<li>The deterministic mock model provider</li>
<li>Local development authentication</li>
<li>Azure Cosmos DB storage</li>
<li>The Linux Cosmos DB emulator</li>
<li>The React web interface</li>
</ul>
<p>This combination is useful because it exercises the real database integration while keeping the model response deterministic and free. It isolates the application and data behavior from model availability, quota, and token cost.</p>
<p>I tested version <code>0.5.3</code> from source. The public quick-start command is:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent@latest bootstrap customer-support-agent `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --template customer-support-ts `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --provider mock `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --auth local `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --storage cosmos `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --local emulator `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --yes</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <code>bootstrap</code> command does more than copy files. It:</p>
<ol>
<li>Resolves the selected scenario and features.</li>
<li>Generates the API, web application, packages, tests, and infrastructure.</li>
<li>Creates the local emulator configuration.</li>
<li>Installs the project dependencies.</li>
<li>Initializes a Git repository.</li>
<li>Links a local project context.</li>
</ol>
<p>It does <strong>not</strong> create Azure resources unless deployment is explicitly requested.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">Prerequisites<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites">​</a></h2>
<p>To follow the same emulator-backed path, install:</p>
<ul>
<li>Node.js 20 or later</li>
<li>Git</li>
<li>Docker Desktop using Linux containers</li>
</ul>
<p>The application uses local ports <code>3000</code>, <code>5173</code>, <code>8080</code>, <code>8081</code>, and <code>1234</code>, so make sure they are available.</p>
<p>If you want the fastest possible first run and do not need durable local data, use in-memory storage instead:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent@latest bootstrap customer-support-agent --yes</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That path does not require Docker.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="starting-the-complete-application">Starting the complete application<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#starting-the-complete-application" class="hash-link" aria-label="Direct link to Starting the complete application" title="Direct link to Starting the complete application">​</a></h2>
<p>After generation, start the application:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">cd customer-support-agent</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run dev</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For the emulator configuration, this single command performs several steps:</p>
<ol>
<li>Starts the Cosmos DB Linux emulator with Docker Compose.</li>
<li>Waits for the emulator health check.</li>
<li>Creates the database and containers idempotently.</li>
<li>Starts the Express API on <code>http://localhost:3000</code>.</li>
<li>Starts the React application on <code>http://localhost:5173</code>.</li>
</ol>
<p>The emulator's Data Explorer is also available at <code>http://localhost:1234</code>.</p>
<p>The first run takes longer because Docker must download the emulator image and npm must install the generated application's dependencies. Once those layers are available locally, subsequent starts are much faster.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="touring-the-generated-experience">Touring the generated experience<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#touring-the-generated-experience" class="hash-link" aria-label="Direct link to Touring the generated experience" title="Direct link to Touring the generated experience">​</a></h2>
<p>The customer-support application opens with five work areas:</p>
<ul>
<li><strong>Chat</strong> for context-aware conversations and memory</li>
<li><strong>Knowledge</strong> for document ingestion and retrieval</li>
<li><strong>Support</strong> for ticket workflows</li>
<li><strong>Agent runs</strong> for planner, specialist, and reviewer traces</li>
<li><strong>Operations</strong> for runtime diagnostics</li>
</ul>
<p>The header clearly showed that I was using the <code>mock</code> provider and <code>cosmos</code> storage. The local identity panel used:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Tenant: tenant-demo</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">User:   user-demo</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>These are development identities, not a production authentication mechanism. The generated application blocks local authentication and the mock provider in production.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="proving-durable-memory">Proving durable memory<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#proving-durable-memory" class="hash-link" aria-label="Direct link to Proving durable memory" title="Direct link to Proving durable memory">​</a></h2>
<p>The most useful part of the walkthrough was testing memory as application data rather than hidden prompt text.</p>
<p>In the <strong>Chat</strong> tab, I saved this customer preference:</p>
<blockquote>
<p>The customer prefers deployment notifications in Microsoft Teams.</p>
</blockquote>
<p>The application wrote a memory document to Cosmos DB with the tenant, user, agent, thread, retention class, provenance, schema version, and embedding metadata.</p>
<p>I then asked:</p>
<blockquote>
<p>What notification channel does this customer prefer?</p>
</blockquote>
<p>Because the sample uses the deterministic local provider, the answer itself is intentionally simple:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Local demo response: What notification channel does this customer prefer?</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The important result was the attached citation. Expanding it showed the retrieved preference:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">preference</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">The customer prefers deployment notifications in Microsoft Teams.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The API response also included a retrieval trace containing the tenant, user, selected memory ID, embedding version, timestamp, and correlation ID. That makes memory retrieval inspectable instead of silently injecting data into a prompt.</p>
<p>You can create the same memory directly through the API:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$headers = @{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "x-tenant-id"      = "tenant-demo"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "x-user-id"        = "user-demo"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "x-correlation-id" = "memory-demo-001"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$body = @{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  type           = "preference"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  content        = "The customer prefers deployment notifications in Microsoft Teams."</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  threadId       = "web-session"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  interactionId  = "interaction-001"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  retentionClass = "standard"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">} | ConvertTo-Json</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Invoke-RestMethod `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -Method Post `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -Uri "http://localhost:3000/api/memories" `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -Headers $headers `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -ContentType "application/json" `</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -Body $body</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="verifying-tenant-and-user-isolation">Verifying tenant and user isolation<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#verifying-tenant-and-user-isolation" class="hash-link" aria-label="Direct link to Verifying tenant and user isolation" title="Direct link to Verifying tenant and user isolation">​</a></h2>
<p>Memory is only useful when its security boundary is correct.</p>
<p>I changed the local user from <code>user-demo</code> to <code>user-other</code> and asked the same question. The second user received no memory citation. Querying the memory endpoint confirmed the difference:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">user-demo  -&gt; 1 memory item</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">user-other -&gt; 0 memory items</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The retrieval traces told the same story:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">user-demo  -&gt; selected the stored preference memory</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">user-other -&gt; selected no memory IDs</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This is a small test, but it verifies an important architectural decision: tenant and user scope are carried through authentication, partitioning, storage, and retrieval. They are not only UI filters.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="looking-at-diagnostics">Looking at diagnostics<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#looking-at-diagnostics" class="hash-link" aria-label="Direct link to Looking at diagnostics" title="Direct link to Looking at diagnostics">​</a></h2>
<p>The <strong>Operations</strong> tab exposes redacted runtime diagnostics. After creating and retrieving the preference, my local run reported:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cosmos operations: 3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Request charge:    3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Errors:            0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The recent-operation list included the create and vector-query operations with duration, request charge, and correlation ID. Prompts and document bodies were not captured by default.</p>
<p>Treat emulator request-unit values as development signals rather than production measurements. The Linux emulator is still a preview, and its request charges, vector indexing, and hierarchical partition behavior can differ from Azure Cosmos DB. Measure representative workloads against the Azure service before making production capacity decisions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="running-the-quality-gates">Running the quality gates<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#running-the-quality-gates" class="hash-link" aria-label="Direct link to Running the quality gates" title="Direct link to Running the quality gates">​</a></h2>
<p>The CLI includes two useful commands:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent doctor .</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent validate .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>doctor</code> checks configuration, secret hygiene, security patterns, and multi-tenant partitioning. My generated project returned:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">HEALTHY No static safety issues found</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Doctor 0 error(s), 0 warning(s), 1 info</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>validate</code> runs the generated project's complete quality gate. In my test, it successfully completed:</p>
<ul>
<li>TypeScript type checking for the API and web application</li>
<li>A production Vite build</li>
<li>8 unit tests</li>
<li>5 security tests</li>
<li>2 cost tests</li>
<li>Bicep template validation</li>
</ul>
<p>I also validated the generator itself before creating the sample: all 58 generator tests passed, followed by a successful TypeScript build and package creation.</p>
<p>The security tests are especially valuable for an agent starter. They verify behaviors such as production authentication requirements, tenant isolation, and protection of consequential actions instead of leaving those controls as documentation-only recommendations.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-the-generated-cosmos-db-path-gets-right">What the generated Cosmos DB path gets right<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#what-the-generated-cosmos-db-path-gets-right" class="hash-link" aria-label="Direct link to What the generated Cosmos DB path gets right" title="Direct link to What the generated Cosmos DB path gets right">​</a></h2>
<p>The generated application applies several patterns that matter when an agent moves beyond a prototype:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scoped-data-modeling">Scoped data modeling<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#scoped-data-modeling" class="hash-link" aria-label="Direct link to Scoped data modeling" title="Direct link to Scoped data modeling">​</a></h3>
<p>Memory documents include explicit tenant, user, agent, and thread scope. Related data needed for retrieval is stored together, while schema and embedding versions make future evolution possible.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="partition-aware-access">Partition-aware access<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#partition-aware-access" class="hash-link" aria-label="Direct link to Partition-aware access" title="Direct link to Partition-aware access">​</a></h3>
<p>The production path uses hierarchical partition keys aligned with tenant and user access patterns. This reduces accidental cross-tenant queries and gives the application a predictable isolation boundary.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="a-reusable-client">A reusable client<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#a-reusable-client" class="hash-link" aria-label="Direct link to A reusable client" title="Direct link to A reusable client">​</a></h3>
<p>The Azure Cosmos DB client is reused instead of being created for every request. Reusing a singleton client is essential for efficient connection management and predictable latency.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bounded-and-parameterized-retrieval">Bounded and parameterized retrieval<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#bounded-and-parameterized-retrieval" class="hash-link" aria-label="Direct link to Bounded and parameterized retrieval" title="Direct link to Bounded and parameterized retrieval">​</a></h3>
<p>Vector and document queries are bounded and parameterized. The caller cannot inject query text, and retrieval does not return an unlimited result set.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="optimistic-concurrency">Optimistic concurrency<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#optimistic-concurrency" class="hash-link" aria-label="Direct link to Optimistic concurrency" title="Direct link to Optimistic concurrency">​</a></h3>
<p>Protected state transitions use ETags. This is important for approval workflows, where two callers must not silently overwrite each other's decisions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="observable-database-operations">Observable database operations<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#observable-database-operations" class="hash-link" aria-label="Direct link to Observable database operations" title="Direct link to Observable database operations">​</a></h3>
<p>Request charge, duration, operation type, errors, and correlation IDs are available without recording prompts or document bodies by default.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="moving-from-local-development-to-azure">Moving from local development to Azure<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#moving-from-local-development-to-azure" class="hash-link" aria-label="Direct link to Moving from local development to Azure" title="Direct link to Moving from local development to Azure">​</a></h2>
<p>The local mock/emulator combination is only one adapter configuration. The production path replaces:</p>
<table><thead><tr><th>Local development</th><th>Azure production</th></tr></thead><tbody><tr><td>Local identity headers</td><td>Microsoft Entra ID tokens</td></tr><tr><td>Mock or Ollama</td><td>Azure OpenAI or another configured provider</td></tr><tr><td>Cosmos DB emulator</td><td>Azure Cosmos DB</td></tr><tr><td>Emulator key</td><td>Managed Identity</td></tr><tr><td>Local diagnostics</td><td>Azure Monitor and Application Insights</td></tr></tbody></table>
<p>Before deployment, configure the Entra application values and model endpoint, then run:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd auth login</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set ENTRA_TENANT_ID "&lt;tenant-id&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set ENTRA_AUDIENCE "&lt;api-audience&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set ENTRA_CLIENT_ID "&lt;spa-client-id&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set ENTRA_SCOPE "&lt;api-scope&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set AI_PROVIDER "azure-openai"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set AZURE_OPENAI_ENDPOINT "&lt;endpoint&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd env set AZURE_OPENAI_CHAT_DEPLOYMENT "&lt;deployment&gt;"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent prepare-azure . --environment customer-support-agent-dev</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">azd up</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>prepare-azure</code> is a readiness check. It verifies Azure Developer CLI authentication, Entra configuration, the selected production provider, Cosmos DB capacity choices, and required settings without creating resources. <code>azd up</code> is the step that can provision billable resources.</p>
<p>Azure OpenAI capacity is bring-your-own, so confirm that the selected region and deployment have quota before deploying. The generated production infrastructure uses a user-assigned Managed Identity; grant it the required Azure Cosmos DB data-plane role and the <code>Cognitive Services OpenAI User</code> role.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-i-learned-from-the-end-to-end-run">What I learned from the end-to-end run<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#what-i-learned-from-the-end-to-end-run" class="hash-link" aria-label="Direct link to What I learned from the end-to-end run" title="Direct link to What I learned from the end-to-end run">​</a></h2>
<p>Three aspects stood out.</p>
<p>First, <strong>the starter treats memory as a product feature</strong>. It has scope, provenance, retention, citations, retrieval traces, and diagnostics. That is much stronger than appending previous messages to every prompt.</p>
<p>Second, <strong>local development is genuinely local</strong>. I exercised Cosmos DB persistence and vector retrieval without creating an Azure account or supplying a model key.</p>
<p>Third, <strong>the path to production is visible from the beginning</strong>. Entra ID, Managed Identity, infrastructure, diagnostics, capacity, and validation are not postponed until after the prototype succeeds.</p>
<p>There are also practical caveats:</p>
<ul>
<li>Docker is required for the emulator-backed path.</li>
<li>The first emulator image download can take time.</li>
<li>The mock provider proves application behavior, not model quality.</li>
<li>Emulator performance and request charges are not production benchmarks.</li>
<li>Azure deployment still requires identity design, quota, capacity, and cost decisions.</li>
</ul>
<p>Those are reasonable boundaries. The goal of a starter should be to remove repetitive work while keeping important production decisions explicit.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="frequently-asked-questions">Frequently asked questions<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#frequently-asked-questions" class="hash-link" aria-label="Direct link to Frequently asked questions" title="Direct link to Frequently asked questions">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="can-i-build-this-azure-cosmos-db-ai-agent-without-an-azure-subscription">Can I build this Azure Cosmos DB AI agent without an Azure subscription?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#can-i-build-this-azure-cosmos-db-ai-agent-without-an-azure-subscription" class="hash-link" aria-label="Direct link to Can I build this Azure Cosmos DB AI agent without an Azure subscription?" title="Direct link to Can I build this Azure Cosmos DB AI agent without an Azure subscription?">​</a></h3>
<p>Yes. The default local path uses a deterministic mock model and either in-memory storage or the Azure Cosmos DB Linux emulator. You do not need an Azure subscription or model API key for the first run.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="does-the-local-sample-require-an-ai-model-api-key">Does the local sample require an AI model API key?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#does-the-local-sample-require-an-ai-model-api-key" class="hash-link" aria-label="Direct link to Does the local sample require an AI model API key?" title="Direct link to Does the local sample require an AI model API key?">​</a></h3>
<p>No. The mock provider produces deterministic development responses. You can later configure Azure OpenAI, OpenAI, or Ollama without changing the application contracts.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="how-does-the-sample-isolate-agent-memory">How does the sample isolate agent memory?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#how-does-the-sample-isolate-agent-memory" class="hash-link" aria-label="Direct link to How does the sample isolate agent memory?" title="Direct link to How does the sample isolate agent memory?">​</a></h3>
<p>Authentication context carries tenant and user identifiers through storage and retrieval. A memory saved for one user is not returned to another user, even within the same tenant.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="is-the-cosmos-db-emulator-equivalent-to-the-azure-service">Is the Cosmos DB emulator equivalent to the Azure service?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#is-the-cosmos-db-emulator-equivalent-to-the-azure-service" class="hash-link" aria-label="Direct link to Is the Cosmos DB emulator equivalent to the Azure service?" title="Direct link to Is the Cosmos DB emulator equivalent to the Azure service?">​</a></h3>
<p>No. It is ideal for local development, but request charges, vector indexing, performance, and hierarchical partition behavior can differ from Azure Cosmos DB. Test representative workloads against Azure before making production capacity decisions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="how-do-i-move-the-generated-agent-to-azure">How do I move the generated agent to Azure?<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#how-do-i-move-the-generated-agent-to-azure" class="hash-link" aria-label="Direct link to How do I move the generated agent to Azure?" title="Direct link to How do I move the generated agent to Azure?">​</a></h3>
<p>Configure Microsoft Entra ID, an Azure OpenAI deployment, and the required <code>azd</code> environment values. Run <code>create-cosmos-agent prepare-azure</code> before <code>azd up</code> to validate readiness.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="clean-up">Clean up<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#clean-up" class="hash-link" aria-label="Direct link to Clean up" title="Direct link to Clean up">​</a></h2>
<p>Stop the development process with <code>Ctrl+C</code>, then stop and remove the emulator container:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run emulator:stop</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The generated data remains local to the emulator container lifecycle. If you used the default in-memory configuration instead, restarting the API resets the data.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="try-it-yourself">Try it yourself<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself">​</a></h2>
<p>Start with the repository and end-to-end demo:</p>
<ul>
<li><a href="https://github.com/sajeetharan/cosmos-agent-starter" target="_blank" rel="noopener noreferrer">Azure Cosmos DB Agent Starter on GitHub</a></li>
<li><a href="https://raw.githubusercontent.com/sajeetharan/cosmos-agent-starter/main/docs/media/create-cosmos-agent-end-to-end.mp4" target="_blank" rel="noopener noreferrer">Watch the complete end-to-end video</a></li>
<li><a href="https://github.com/sajeetharan/cosmos-agent-starter/blob/main/docs/media/create-cosmos-agent-end-to-end.srt" target="_blank" rel="noopener noreferrer">Download the captioned walkthrough</a></li>
</ul>
<p>Then generate an application:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx create-cosmos-agent@latest bootstrap my-agent --yes</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cd my-agent</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run dev</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Open <code>http://localhost:5173</code>, save a preference, ask the agent to recall it, switch users, inspect the citation, and run the validation commands.</p>
<p>That short workflow demonstrates the bigger idea behind the project: start with a zero-cost local agent, preserve the application contracts, and move deliberately toward a secure Azure deployment.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="related-reading">Related reading<a href="https://www.sajeetharan.dev/blogs/build-an-ai-agent-with-azure-cosmos-db#related-reading" class="hash-link" aria-label="Direct link to Related reading" title="Direct link to Related reading">​</a></h2>
<ul>
<li><a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db">Building DevGlobe with Azure Cosmos DB and AI Agents</a></li>
<li><a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman">Turning Coding Agents into Azure Cosmos DB Experts with Scott Hanselman</a></li>
<li><a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents">What Six Months of Building AI Agent Skills Taught Me About Writing for Machines</a></li>
</ul>]]></content:encoded>
            <category>azure-cosmos-db</category>
            <category>ai-agents</category>
            <category>typescript</category>
            <category>react</category>
            <category>vector-search</category>
            <category>developer-tools</category>
            <category>azure</category>
        </item>
        <item>
            <title><![CDATA[Building DevGlobe with Azure Cosmos DB and AI Agents]]></title>
            <link>https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db</link>
            <guid>https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db</guid>
            <pubDate>Thu, 01 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How DevGlobe uses Azure Cosmos DB, vector search, MCP, and Azure Functions to power an open-source talent graph for developers and AI agents.]]></description>
            <content:encoded><![CDATA[<p>Finding a developer by name is easy. Finding the right developer for a problem is much harder.</p>
<p>A GitHub profile can show repositories. Stack Overflow can show answers. A professional network can show job titles. But none of those views, on their own, answer questions such as:</p>
<ul>
<li>Who has recent evidence of working with a specific technology?</li>
<li>Which developers match the needs of an open-source repository?</li>
<li>Who is active in a particular region or community?</li>
<li>Can an AI agent discover a relevant expert without exposing private contact details?</li>
</ul>
<p>Those questions led me to build <a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer">DevGlobe</a>, an open-source talent graph for humans and AI agents. What started as an interactive 3D map became a search, data, and consent problem—and Azure Cosmos DB became the foundation that connected those pieces.</p>
<div class="blog-media-frame"><p><a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="DevGlobe connects developers and AI agents through an open talent graph" src="https://www.sajeetharan.dev/assets/images/devglobe-product-037f27d4ac7ef4bfd690bc9179ea9ebc.png" width="1536" height="1024" class="img_ev3q"></a></p></div>
<p><strong><a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer">Explore DevGlobe and discover developers, contribution opportunities, live coding activity, and agent-ready tools →</a></strong></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-idea-discovery-based-on-evidence-not-popularity">The idea: discovery based on evidence, not popularity<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#the-idea-discovery-based-on-evidence-not-popularity" class="hash-link" aria-label="Direct link to The idea: discovery based on evidence, not popularity" title="Direct link to The idea: discovery based on evidence, not popularity">​</a></h2>
<p>Developer discovery often becomes a popularity contest. Follower counts, total stars, and reputation are useful signals, but they should not become unsupported conclusions about a person's expertise or suitability.</p>
<p>DevGlobe brings together public evidence from sources such as GitHub and Stack Overflow, then presents it through:</p>
<ul>
<li>An interactive 3D developer globe</li>
<li>Search by skills, technologies, roles, names, and locations</li>
<li>Developer profiles with contribution evidence</li>
<li>Repository-to-developer matching</li>
<li>A VS Code extension for opt-in live presence</li>
<li>A hosted MCP server for AI-agent discovery</li>
<li>Consent-gated introductions for verified agents</li>
</ul>
<p>The goal is not to declare that one developer is "better" than another. The goal is to make relevant public evidence easier to discover and explain.</p>
<p>You can explore the live project at <a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer">devglobe.dev</a> or view the source on <a href="https://github.com/sajeetharan/devglobe" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-azure-cosmos-db-fit-the-problem">Why Azure Cosmos DB fit the problem<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#why-azure-cosmos-db-fit-the-problem" class="hash-link" aria-label="Direct link to Why Azure Cosmos DB fit the problem" title="Direct link to Why Azure Cosmos DB fit the problem">​</a></h2>
<p>DevGlobe combines several workloads that look related in the interface but behave very differently in storage:</p>
<ol>
<li>Public developer profiles change comparatively slowly and are read frequently.</li>
<li>Search needs both exact text signals and semantic similarity.</li>
<li>Live coding presence changes every few seconds and should expire automatically.</li>
<li>Private coding statistics belong only to the developer who generated them.</li>
<li>Introduction requests have a durable, consent-driven lifecycle.</li>
<li>Agents need bounded, structured access to public data and protected workflows.</li>
</ol>
<p>Trying to force all of those workloads through one generic data path would make the system harder to scale and harder to reason about.</p>
<p>Azure Cosmos DB gave me a flexible document model, low-latency reads, vector search, automatic indexing, and workload-specific containers. More importantly, it let the architecture evolve as DevGlobe grew from a visualization into an agent-ready platform.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-high-level-architecture">The high-level architecture<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#the-high-level-architecture" class="hash-link" aria-label="Direct link to The high-level architecture" title="Direct link to The high-level architecture">​</a></h2>
<p>The production system separates interactive product traffic, high-volume public reads, static snapshots, and scheduled ingestion:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">GitHub + Stack Overflow + public signals</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            ingestion jobs</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                  |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          Azure Cosmos DB</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        /        |         \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> profiles    activities    workflow state</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    |            |              |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    +------ search APIs --------+</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">           /             \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> Azure Functions     Azure Container Apps</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> public reads        web, auth, MCP, mutations</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">           \             /</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">           humans + AI agents</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="blog-media-frame"><p><img decoding="async" loading="lazy" alt="DevGlobe production architecture showing public signals, Azure Cosmos DB, Azure Functions, Blob Storage, Container Apps, humans, and AI agents" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjgyMCIgdmlld0JveD0iMCAwIDE0MDAgODIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyI+CiAgPHRpdGxlIGlkPSJ0aXRsZSI+RGV2R2xvYmUgcHJvZHVjdGlvbiBhcmNoaXRlY3R1cmU8L3RpdGxlPgogIDxkZXNjIGlkPSJkZXNjIj5QdWJsaWMgZGV2ZWxvcGVyIHNpZ25hbHMgZmxvdyB0aHJvdWdoIGluZ2VzdGlvbiBpbnRvIEF6dXJlIENvc21vcyBEQiwgdGhlbiB0aHJvdWdoIEF6dXJlIEZ1bmN0aW9ucywgQmxvYiBTdG9yYWdlLCBBenVyZSBDb250YWluZXIgQXBwcywgQVBJcywgYW5kIE1DUCB0byBodW1hbnMgYW5kIEFJIGFnZW50cy48L2Rlc2M+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJhY2tncm91bmQiIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIxIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMDcxMTFkIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzBjMjAzMCIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYWNjZW50IiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzIyZDNlZSIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMxNGI4YTYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8ZmlsdGVyIGlkPSJzaGFkb3ciIHg9Ii0yMCUiIHk9Ii0yMCUiIHdpZHRoPSIxNDAlIiBoZWlnaHQ9IjE0MCUiPgogICAgICA8ZmVEcm9wU2hhZG93IGR4PSIwIiBkeT0iMTIiIHN0ZERldmlhdGlvbj0iMTQiIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuMjgiLz4KICAgIDwvZmlsdGVyPgogICAgPG1hcmtlciBpZD0iYXJyb3ciIG1hcmtlcldpZHRoPSIxMCIgbWFya2VySGVpZ2h0PSIxMCIgcmVmWD0iOCIgcmVmWT0iMyIgb3JpZW50PSJhdXRvIiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiPgogICAgICA8cGF0aCBkPSJNMCwwIEwwLDYgTDksMyB6IiBmaWxsPSIjNGZkMWU1Ii8+CiAgICA8L21hcmtlcj4KICAgIDxzdHlsZT4KICAgICAgLmxhYmVse2ZvbnQ6NjAwIDI0cHggSW50ZXIsQXJpYWwsc2Fucy1zZXJpZjtmaWxsOiNmOGZhZmN9CiAgICAgIC5zbWFsbHtmb250OjUwMCAxN3B4IEludGVyLEFyaWFsLHNhbnMtc2VyaWY7ZmlsbDojOTRhM2I4fQogICAgICAua2lja2Vye2ZvbnQ6NzAwIDE1cHggSW50ZXIsQXJpYWwsc2Fucy1zZXJpZjtmaWxsOiM2N2U4Zjk7bGV0dGVyLXNwYWNpbmc6MnB4fQogICAgICAubm9kZXtmaWxsOiMxMDI0MzU7c3Ryb2tlOiMyOTQ2NWM7c3Ryb2tlLXdpZHRoOjJ9CiAgICAgIC5jb3Jle2ZpbGw6IzBiMzA0MDtzdHJva2U6IzIyZDNlZTtzdHJva2Utd2lkdGg6M30KICAgICAgLmZsb3d7ZmlsbDpub25lO3N0cm9rZTojNGZkMWU1O3N0cm9rZS13aWR0aDozO21hcmtlci1lbmQ6dXJsKCNhcnJvdyl9CiAgICA8L3N0eWxlPgogIDwvZGVmcz4KICA8cmVjdCB3aWR0aD0iMTQwMCIgaGVpZ2h0PSI4MjAiIHJ4PSIzNCIgZmlsbD0idXJsKCNiYWNrZ3JvdW5kKSIvPgogIDx0ZXh0IHg9IjcwIiB5PSI3NCIgY2xhc3M9ImtpY2tlciI+REVWR0xPQkUgwrcgUFJPRFVDVElPTiBBUkNISVRFQ1RVUkU8L3RleHQ+CiAgPHRleHQgeD0iNzAiIHk9IjEyMiIgY2xhc3M9ImxhYmVsIiBzdHlsZT0iZm9udC1zaXplOjM0cHgiPkV2aWRlbmNlIGluLiBCb3VuZGVkIGRpc2NvdmVyeSBvdXQuPC90ZXh0PgoKICA8ZyBmaWx0ZXI9InVybCgjc2hhZG93KSI+CiAgICA8cmVjdCB4PSI3MCIgeT0iMjEwIiB3aWR0aD0iMjcwIiBoZWlnaHQ9IjIyMCIgcng9IjI0IiBjbGFzcz0ibm9kZSIvPgogICAgPHRleHQgeD0iMTA1IiB5PSIyNTUiIGNsYXNzPSJraWNrZXIiPlBVQkxJQyBTSUdOQUxTPC90ZXh0PgogICAgPHRleHQgeD0iMTA1IiB5PSIzMDciIGNsYXNzPSJsYWJlbCI+R2l0SHViPC90ZXh0PgogICAgPHRleHQgeD0iMTA1IiB5PSIzNDYiIGNsYXNzPSJsYWJlbCI+U3RhY2sgT3ZlcmZsb3c8L3RleHQ+CiAgICA8dGV4dCB4PSIxMDUiIHk9IjM4NSIgY2xhc3M9ImxhYmVsIj5Db21tdW5pdHkgZXZpZGVuY2U8L3RleHQ+CiAgPC9nPgoKICA8ZyBmaWx0ZXI9InVybCgjc2hhZG93KSI+CiAgICA8cmVjdCB4PSI0MTUiIHk9IjIxMCIgd2lkdGg9IjI2MCIgaGVpZ2h0PSIyMjAiIHJ4PSIyNCIgY2xhc3M9Im5vZGUiLz4KICAgIDx0ZXh0IHg9IjQ1MCIgeT0iMjU1IiBjbGFzcz0ia2lja2VyIj5EQVRBIFBJUEVMSU5FPC90ZXh0PgogICAgPHRleHQgeD0iNDUwIiB5PSIzMDciIGNsYXNzPSJsYWJlbCI+SW5nZXN0PC90ZXh0PgogICAgPHRleHQgeD0iNDUwIiB5PSIzNDYiIGNsYXNzPSJsYWJlbCI+RW5yaWNoPC90ZXh0PgogICAgPHRleHQgeD0iNDUwIiB5PSIzODUiIGNsYXNzPSJsYWJlbCI+RW1iZWQ8L3RleHQ+CiAgPC9nPgoKICA8ZyBmaWx0ZXI9InVybCgjc2hhZG93KSI+CiAgICA8cmVjdCB4PSI3NTAiIHk9IjE4MCIgd2lkdGg9IjMxMCIgaGVpZ2h0PSIyODAiIHJ4PSIyOCIgY2xhc3M9ImNvcmUiLz4KICAgIDx0ZXh0IHg9Ijc5MCIgeT0iMjMyIiBjbGFzcz0ia2lja2VyIj5EQVRBICsgU0VBUkNIICsgU1RBVEU8L3RleHQ+CiAgICA8dGV4dCB4PSI3OTAiIHk9IjI4NiIgY2xhc3M9ImxhYmVsIiBzdHlsZT0iZm9udC1zaXplOjI5cHgiPkF6dXJlIENvc21vcyBEQjwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc5MCIgeT0iMzMzIiBjbGFzcz0ic21hbGwiPkRldmVsb3BlciBwcm9maWxlcyArIGVtYmVkZGluZ3M8L3RleHQ+CiAgICA8dGV4dCB4PSI3OTAiIHk9IjM2OSIgY2xhc3M9InNtYWxsIj5BY3Rpdml0aWVzICsgbGl2ZSBwcmVzZW5jZTwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc5MCIgeT0iNDA1IiBjbGFzcz0ic21hbGwiPkNvbnNlbnQgKyB3b3JrZmxvdyBzdGF0ZTwvdGV4dD4KICA8L2c+CgogIDxnIGZpbHRlcj0idXJsKCNzaGFkb3cpIj4KICAgIDxyZWN0IHg9IjExMzUiIHk9IjE2MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMzAiIHJ4PSIyMiIgY2xhc3M9Im5vZGUiLz4KICAgIDx0ZXh0IHg9IjExNjUiIHk9IjIwNSIgY2xhc3M9ImtpY2tlciI+UFVCTElDIFJFQURTPC90ZXh0PgogICAgPHRleHQgeD0iMTE2NSIgeT0iMjUyIiBjbGFzcz0ibGFiZWwiPkZ1bmN0aW9uczwvdGV4dD4KCiAgICA8cmVjdCB4PSIxMTM1IiB5PSIzMzAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTMwIiByeD0iMjIiIGNsYXNzPSJub2RlIi8+CiAgICA8dGV4dCB4PSIxMTY1IiB5PSIzNzUiIGNsYXNzPSJraWNrZXIiPlNOQVBTSE9UUzwvdGV4dD4KICAgIDx0ZXh0IHg9IjExNjUiIHk9IjQyMiIgY2xhc3M9ImxhYmVsIj5CbG9iIFN0b3JhZ2U8L3RleHQ+CiAgPC9nPgoKICA8ZyBmaWx0ZXI9InVybCgjc2hhZG93KSI+CiAgICA8cmVjdCB4PSI3NTAiIHk9IjU2MCIgd2lkdGg9IjMxMCIgaGVpZ2h0PSIxNjAiIHJ4PSIyNCIgY2xhc3M9Im5vZGUiLz4KICAgIDx0ZXh0IHg9Ijc5MCIgeT0iNjA3IiBjbGFzcz0ia2lja2VyIj5QUk9EVUNUICsgUFJJVkFURSBBQ1RJT05TPC90ZXh0PgogICAgPHRleHQgeD0iNzkwIiB5PSI2NTUiIGNsYXNzPSJsYWJlbCI+QXp1cmUgQ29udGFpbmVyIEFwcHM8L3RleHQ+CiAgICA8dGV4dCB4PSI3OTAiIHk9IjY5MCIgY2xhc3M9InNtYWxsIj5OZXh0LmpzIMK3IEF1dGggwrcgTUNQIMK3IE11dGF0aW9uczwvdGV4dD4KICA8L2c+CgogIDxnIGZpbHRlcj0idXJsKCNzaGFkb3cpIj4KICAgIDxyZWN0IHg9IjExMzUiIHk9IjU2MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxNjAiIHJ4PSIyNCIgY2xhc3M9Im5vZGUiLz4KICAgIDx0ZXh0IHg9IjExNjUiIHk9IjYwNyIgY2xhc3M9ImtpY2tlciI+RVhQRVJJRU5DRTwvdGV4dD4KICAgIDx0ZXh0IHg9IjExNjUiIHk9IjY1NSIgY2xhc3M9ImxhYmVsIj5IdW1hbnM8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTY1IiB5PSI2OTQiIGNsYXNzPSJsYWJlbCI+QUkgYWdlbnRzPC90ZXh0PgogIDwvZz4KCiAgPHBhdGggZD0iTTM0MCAzMjAgSDQwMCIgY2xhc3M9ImZsb3ciLz4KICA8cGF0aCBkPSJNNjc1IDMyMCBINzM1IiBjbGFzcz0iZmxvdyIvPgogIDxwYXRoIGQ9Ik0xMDYwIDI0NSBIMTEyMCIgY2xhc3M9ImZsb3ciLz4KICA8cGF0aCBkPSJNMTA2MCAzOTAgSDExMjAiIGNsYXNzPSJmbG93Ii8+CiAgPHBhdGggZD0iTTkwNSA0NjAgVjU0NSIgY2xhc3M9ImZsb3ciLz4KICA8cGF0aCBkPSJNMTA2MCA2NDAgSDExMjAiIGNsYXNzPSJmbG93Ii8+CiAgPHBhdGggZD0iTTEyMzUgNDYwIFY1NDUiIGNsYXNzPSJmbG93Ii8+CgogIDx0ZXh0IHg9IjcwIiB5PSI3NzUiIGNsYXNzPSJzbWFsbCI+VGV4dCArIHZlY3RvciBzZWFyY2ggwrcgVFRMLWJhY2tlZCBwcmVzZW5jZSDCtyBjb25zZW50LWdhdGVkIGludHJvZHVjdGlvbnMgwrcgbWFjaGluZS1yZWFkYWJsZSBjb250cmFjdHM8L3RleHQ+Cjwvc3ZnPgo=" width="1400" height="820" class="img_ev3q"></p></div>
<p>The major runtime pieces are:</p>
<ul>
<li><strong>Next.js, React, and Three.js</strong> for the product and interactive globe</li>
<li><strong>Azure Container Apps</strong> for the dynamic web application, authentication, private mutations, share metadata, and hosted MCP endpoint</li>
<li><strong>Azure Functions</strong> for high-volume public APIs, scheduled ingestion, and snapshot generation</li>
<li><strong>Azure Cosmos DB</strong> for profiles, activities, search, live presence, coding statistics, and workflow state</li>
<li><strong>Azure Blob Storage</strong> for a compressed developer snapshot that browsers can download efficiently</li>
<li><strong>Azure OpenAI embeddings</strong> for semantic and hybrid developer search</li>
</ul>
<p>This split is intentional. Not every request needs to reach the full Next.js application, and not every browser load needs to query the database directly.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="architecture-and-implementation-references">Architecture and implementation references<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#architecture-and-implementation-references" class="hash-link" aria-label="Direct link to Architecture and implementation references" title="Direct link to Architecture and implementation references">​</a></h3>
<p>The architecture is open for inspection. These documents go deeper than a single article can:</p>
<ul>
<li><a href="https://github.com/sajeetharan/devglobe/blob/main/docs/azure-backend.md" target="_blank" rel="noopener noreferrer">Azure backend and production traffic split</a></li>
<li><a href="https://github.com/sajeetharan/devglobe/blob/main/docs/mcp-server.md" target="_blank" rel="noopener noreferrer">Hosted MCP server and consent lifecycle</a></li>
<li><a href="https://github.com/sajeetharan/devglobe/blob/main/docs/agent-readiness.md" target="_blank" rel="noopener noreferrer">Agent-readiness and machine-readable discovery</a></li>
<li><a href="https://www.devglobe.dev/openapi.json" target="_blank" rel="noopener noreferrer">Public OpenAPI description</a></li>
<li><a href="https://sajeetharan.github.io/devglobe/" target="_blank" rel="noopener noreferrer">Developer documentation</a></li>
<li><a href="https://github.com/sajeetharan/devglobe" target="_blank" rel="noopener noreferrer">Complete source repository</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="modeling-developer-profiles-as-useful-documents">Modeling developer profiles as useful documents<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#modeling-developer-profiles-as-useful-documents" class="hash-link" aria-label="Direct link to Modeling developer profiles as useful documents" title="Direct link to Modeling developer profiles as useful documents">​</a></h2>
<p>A developer profile is naturally document-shaped. Identity, location, languages, repository summaries, contribution totals, community credentials, search text, and embeddings are commonly retrieved together.</p>
<p>That makes a denormalized profile document practical for the primary read path. The interface can render a developer card without coordinating several joins, while search APIs can project only the fields required for a result.</p>
<p>The important design choice is to keep facts and conclusions separate.</p>
<p>DevGlobe stores public evidence such as:</p>
<ul>
<li>GitHub login and profile metadata</li>
<li>Languages and repository signals</li>
<li>Stars, commits, forks, and watchers</li>
<li>Stack Overflow reputation and engagement</li>
<li>Verified community credentials</li>
<li>Geocoded public location</li>
<li>Search text and vector embeddings</li>
</ul>
<p>Credentials are explicit data, not guesses. A person is not labeled a Google Developer Expert, Microsoft MVP, GitHub Star, or community leader because an algorithm inferred it from popularity. Those tags require verifiable public evidence.</p>
<p>The same principle applies to search results: a relevance score is an ordinal discovery signal, not a probability that someone is suitable for a job.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="combining-text-and-vector-search">Combining text and vector search<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#combining-text-and-vector-search" class="hash-link" aria-label="Direct link to Combining text and vector search" title="Direct link to Combining text and vector search">​</a></h2>
<p>Developer searches do not always use the exact words stored on a profile.</p>
<p>Someone may search for:</p>
<blockquote>
<p>"TypeScript developer working on AI agents in Bengaluru"</p>
</blockquote>
<p>Text search is strong when the query contains names, locations, languages, or exact technologies. Vector search is useful when the intent is expressed through related concepts rather than matching terms. DevGlobe supports text, vector, and hybrid modes so those strengths can complement each other.</p>
<div class="blog-media-frame"><p><a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="DevGlobe Find People experience with skill, location, and GitHub username search over an interactive globe" src="https://www.sajeetharan.dev/assets/images/devglobe-search-0bb1ae7bd83eb258f71e8d69592ecc85.png" width="920" height="620" class="img_ev3q"></a></p></div>
<p>The public <a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer">Find People experience</a> brings those search modes together over the interactive globe. Visitors can search by skills, projects, locations, names, or GitHub usernames, then inspect the public evidence behind each result.</p>
<p>At a high level, the flow is:</p>
<ol>
<li>Parse and normalize the query.</li>
<li>Generate an embedding when semantic search is available.</li>
<li>Retrieve a bounded candidate set from Azure Cosmos DB.</li>
<li>Combine text and semantic evidence.</li>
<li>Return projected public fields with explanations and search signals.</li>
</ol>
<p>The vector query uses <code>VectorDistance</code> against the stored profile embedding and orders a bounded result set by distance. Text search remains available as a fallback, including for contributors running DevGlobe locally without Azure OpenAI.</p>
<p>That fallback matters. A development environment should not become unusable just because an optional AI dependency is unavailable.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="designing-for-bounded-cost-and-predictable-queries">Designing for bounded cost and predictable queries<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#designing-for-bounded-cost-and-predictable-queries" class="hash-link" aria-label="Direct link to Designing for bounded cost and predictable queries" title="Direct link to Designing for bounded cost and predictable queries">​</a></h2>
<p>Search systems can become expensive when every interaction turns into an unbounded cross-partition scan. DevGlobe keeps public APIs bounded and treats the returned fields as part of the contract.</p>
<p>Several practices help:</p>
<ul>
<li>Limit result counts at the API boundary.</li>
<li>Project only fields needed by list and search views.</li>
<li>Keep full profile retrieval separate from result summaries.</li>
<li>Parameterize user-provided values.</li>
<li>Cache and reuse the Cosmos client and container references.</li>
<li>Generate browser snapshots for high-volume read paths.</li>
<li>Keep ephemeral and durable workloads in separate containers.</li>
</ul>
<p>The browser can load the compressed developer snapshot from Blob Storage, while Azure Functions handle public detail and search requests. This reduces pressure on the application container and avoids routing every public read through a server-rendered page.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="live-presence-is-an-expiry-problem">Live presence is an expiry problem<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#live-presence-is-an-expiry-problem" class="hash-link" aria-label="Direct link to Live presence is an expiry problem" title="Direct link to Live presence is an expiry problem">​</a></h2>
<p>The DevGlobe VS Code extension lets a developer opt in to appear on the live globe. It sends a bounded heartbeat every 30 seconds containing:</p>
<ul>
<li>Active language, when enabled</li>
<li>Editor and platform</li>
<li>Session start</li>
<li>Last-seen time</li>
</ul>
<p>It does <strong>not</strong> send source code, file paths, repository names, branches, or keystrokes. Coordinates come from the developer's existing public profile rather than the device.</p>
<p>Live presence has a very different lifecycle from a developer profile. A heartbeat is useful now, but it should not remain forever.</p>
<p>DevGlobe uses a TTL-enabled Cosmos DB container for this workload:</p>
<ul>
<li>A heartbeat is considered live for 90 seconds.</li>
<li>A developer can remain visible as recently coding for 15 minutes.</li>
<li>Cosmos DB TTL removes the item automatically after that window.</li>
</ul>
<p>This is simpler and safer than building a separate cleanup process for expired presence. The data model expresses the retention policy directly.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="private-coding-statistics-use-a-separate-boundary">Private coding statistics use a separate boundary<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#private-coding-statistics-use-a-separate-boundary" class="hash-link" aria-label="Direct link to Private coding statistics use a separate boundary" title="Direct link to Private coding statistics use a separate boundary">​</a></h2>
<p>The extension can also build private, owner-only daily coding totals from consecutive heartbeats. These aggregates are stored separately from public live presence and retained for 400 days.</p>
<p>That separation is important:</p>
<ul>
<li>Public presence answers, "Who has opted in to appear live?"</li>
<li>Private statistics answer, "What does my own coding activity look like over time?"</li>
</ul>
<p>They have different audiences, retention periods, and authorization requirements. Keeping them in separate containers makes those boundaries visible in both the data model and the APIs.</p>
<p>Aggregate writes are best-effort. A statistics failure should never prevent a developer from appearing live.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="from-a-database-api-to-domain-specific-mcp-tools">From a database API to domain-specific MCP tools<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#from-a-database-api-to-domain-specific-mcp-tools" class="hash-link" aria-label="Direct link to From a database API to domain-specific MCP tools" title="Direct link to From a database API to domain-specific MCP tools">​</a></h2>
<p>DevGlobe exposes a hosted Streamable HTTP MCP endpoint:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">https://www.devglobe.dev/mcp</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The easy implementation would have been a generic Cosmos DB query tool. I deliberately did not build that.</p>
<div class="blog-media-frame"><p><a href="https://www.devglobe.dev/agents" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="DevGlobe MCP setup page for connecting GitHub Copilot and other AI agents" src="https://www.sajeetharan.dev/assets/images/devglobe-mcp-agent-setup-40b89da643e92e04303d5feb320fe07c.png" width="920" height="620" class="img_ev3q"></a></p></div>
<p>The <a href="https://www.devglobe.dev/agents" target="_blank" rel="noopener noreferrer">agent setup experience</a> provides connection instructions for GitHub Copilot, VS Code, Claude, Cursor, and direct HTTP clients. Public discovery works without credentials; introductions remain authenticated and consent-gated.</p>
<p>Agents instead receive domain-specific capabilities such as:</p>
<ul>
<li>Search public developer profiles</li>
<li>Inspect a public developer profile</li>
<li>Match developers to a public GitHub repository</li>
<li>Discover trending developers</li>
<li>Find similar developers</li>
<li>Request a consent-gated introduction</li>
<li>Check introduction status</li>
</ul>
<p>This distinction matters. The agent should understand the action it is taking, not merely the database operation underneath it.</p>
<p>Public discovery works anonymously. Introduction requests require a verified agent credential and explicit developer consent. Private contact details are never returned through public discovery.</p>
<p>Cosmos DB persists the workflow state, but the MCP server exposes the domain contract: discover publicly, request transparently, and let the person decide.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="consent-is-data-not-prompt-text">Consent is data, not prompt text<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#consent-is-data-not-prompt-text" class="hash-link" aria-label="Direct link to Consent is data, not prompt text" title="Direct link to Consent is data, not prompt text">​</a></h2>
<p>One of the most important lessons from DevGlobe is that prompts cannot enforce consent.</p>
<p>A reliable introduction workflow needs durable state:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">agent requests introduction</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">request stored with bounded context</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">developer reviews request</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       /         \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   accepts       declines</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      |             |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">status updated and exposed without leaking private data</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The system—not the model—decides which transitions are allowed.</p>
<p>DevGlobe separates public discovery from consequential actions, validates scopes, returns structured errors, and records the consent lifecycle. An agent can help someone find a potential collaborator, but it cannot silently initiate contact or retrieve private details.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-an-agent-readable-product">Building an agent-readable product<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#building-an-agent-readable-product" class="hash-link" aria-label="Direct link to Building an agent-readable product" title="Direct link to Building an agent-readable product">​</a></h2>
<p>Supporting agents involves more than adding an MCP endpoint.</p>
<p>DevGlobe publishes:</p>
<ul>
<li>An OpenAPI description</li>
<li>An API catalog</li>
<li>MCP server metadata</li>
<li>Protected-resource metadata and permission names</li>
<li>Agent Skill metadata with content digests</li>
<li>A Markdown representation for clients that request <code>text/markdown</code></li>
<li>An <code>llms.txt</code> guide</li>
<li>Guarded, read-only WebMCP tools in supported preview browsers</li>
</ul>
<p>This makes the product discoverable through machine-readable contracts rather than requiring an agent to scrape the visual interface.</p>
<p>The API also returns stable error codes and actionable recovery hints. Agents need to know not just that a call failed, but whether they should correct input, authenticate, narrow a query, or stop.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="local-development-without-a-cloud-dependency">Local development without a cloud dependency<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#local-development-without-a-cloud-dependency" class="hash-link" aria-label="Direct link to Local development without a cloud dependency" title="Direct link to Local development without a cloud dependency">​</a></h2>
<p>Open-source projects need a contributor path that does not start with provisioning several Azure resources.</p>
<p>DevGlobe supports three levels:</p>
<ol>
<li><strong>Zero configuration:</strong> bundled sample data and offline text search</li>
<li><strong>Cosmos DB Emulator:</strong> full local database and API development</li>
<li><strong>Azure backend:</strong> vector and hybrid search with Azure OpenAI</li>
</ol>
<p>The application automatically falls back to sample data when Cosmos DB credentials are absent. Contributors can clone the repository, run <code>npm install</code>, and start exploring the product before deciding whether they need the emulator or cloud services.</p>
<p>That progression keeps the first-run experience simple without hiding the production architecture.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-i-would-carry-into-the-next-cosmos-db-project">What I would carry into the next Cosmos DB project<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#what-i-would-carry-into-the-next-cosmos-db-project" class="hash-link" aria-label="Direct link to What I would carry into the next Cosmos DB project" title="Direct link to What I would carry into the next Cosmos DB project">​</a></h2>
<p>Building DevGlobe reinforced several principles that apply beyond developer discovery:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="model-around-access-patterns">Model around access patterns<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#model-around-access-patterns" class="hash-link" aria-label="Direct link to Model around access patterns" title="Direct link to Model around access patterns">​</a></h3>
<p>Embed information retrieved together, project only what each API needs, and separate workloads with different audiences or retention policies.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="use-ttl-for-genuinely-ephemeral-data">Use TTL for genuinely ephemeral data<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#use-ttl-for-genuinely-ephemeral-data" class="hash-link" aria-label="Direct link to Use TTL for genuinely ephemeral data" title="Direct link to Use TTL for genuinely ephemeral data">​</a></h3>
<p>Presence, temporary state, and short-lived signals should not require manual cleanup when the database can enforce expiry.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="keep-semantic-search-bounded">Keep semantic search bounded<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#keep-semantic-search-bounded" class="hash-link" aria-label="Direct link to Keep semantic search bounded" title="Direct link to Keep semantic search bounded">​</a></h3>
<p>Vector search should retrieve a deliberate candidate set, not become an excuse for returning or ranking the entire dataset.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="reuse-the-cosmos-client">Reuse the Cosmos client<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#reuse-the-cosmos-client" class="hash-link" aria-label="Direct link to Reuse the Cosmos client" title="Direct link to Reuse the Cosmos client">​</a></h3>
<p>Creating a client per request wastes connections and adds latency. DevGlobe caches client and container references for reuse.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="design-fallback-paths">Design fallback paths<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#design-fallback-paths" class="hash-link" aria-label="Direct link to Design fallback paths" title="Direct link to Design fallback paths">​</a></h3>
<p>Text search and sample data keep the application useful when embeddings, cloud credentials, or the production backend are unavailable.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="put-trust-boundaries-in-code-and-data">Put trust boundaries in code and data<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#put-trust-boundaries-in-code-and-data" class="hash-link" aria-label="Direct link to Put trust boundaries in code and data" title="Direct link to Put trust boundaries in code and data">​</a></h3>
<p>Authorization, consent, retention, and workflow transitions belong in the system—not only in instructions to an AI model.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-larger-lesson">The larger lesson<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#the-larger-lesson" class="hash-link" aria-label="Direct link to The larger lesson" title="Direct link to The larger lesson">​</a></h2>
<p>DevGlobe began as a visual way to explore the global developer community. Azure Cosmos DB helped it evolve into something broader: a talent graph that humans can explore and agents can use through explicit, bounded contracts.</p>
<p>The most interesting part was not adding AI to a database. It was deciding how data, search, tools, and consent should work together.</p>
<p>An agent-ready platform needs more than powerful queries. It needs:</p>
<ul>
<li>Evidence instead of unsupported conclusions</li>
<li>Context without unnecessary data exposure</li>
<li>Search that explains why a result appeared</li>
<li>Separate boundaries for public and private workloads</li>
<li>Retention policies that match the value of the data</li>
<li>Domain tools instead of unrestricted database access</li>
<li>Human approval for actions that affect people</li>
</ul>
<p>That is the architecture behind DevGlobe—and the direction I believe developer platforms must take as more software is used by both humans and AI agents.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="help-devglobe-grow">Help DevGlobe grow<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#help-devglobe-grow" class="hash-link" aria-label="Direct link to Help DevGlobe grow" title="Direct link to Help DevGlobe grow">​</a></h2>
<p>DevGlobe is independently maintained, open source, and free to use. If the project is useful to you, there are three meaningful ways to support it:</p>
<ol>
<li><strong><a href="https://www.producthunt.com/products/devglobe" target="_blank" rel="noopener noreferrer">Vote for and review DevGlobe on Product Hunt</a></strong> to help more builders discover it.</li>
<li><strong><a href="https://github.com/sajeetharan/devglobe" target="_blank" rel="noopener noreferrer">Star DevGlobe on GitHub</a></strong> to follow the project and signal that the work is valuable.</li>
<li><strong><a href="https://github.com/sponsors/sajeetharan" target="_blank" rel="noopener noreferrer">Sponsor the open-source work</a></strong> to help fund Azure hosting, observability, public-data refreshes, testing, security updates, and ongoing maintenance.</li>
</ol>
<p>Sponsorship never influences developer rankings, search placement, moderation, or access to private information. Those boundaries remain part of the product's public trust contract.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="explore-devglobe">Explore DevGlobe<a href="https://www.sajeetharan.dev/blogs/building-devglobe-with-azure-cosmos-db#explore-devglobe" class="hash-link" aria-label="Direct link to Explore DevGlobe" title="Direct link to Explore DevGlobe">​</a></h2>
<ul>
<li><a href="https://www.devglobe.dev/" target="_blank" rel="noopener noreferrer">Try DevGlobe</a></li>
<li><a href="https://github.com/sajeetharan/devglobe" target="_blank" rel="noopener noreferrer">View the source on GitHub</a></li>
<li><a href="https://www.producthunt.com/products/devglobe" target="_blank" rel="noopener noreferrer">Vote or leave a Product Hunt review</a></li>
<li><a href="https://github.com/sponsors/sajeetharan" target="_blank" rel="noopener noreferrer">Sponsor DevGlobe</a></li>
<li><a href="https://www.devglobe.dev/docs/mcp-server" target="_blank" rel="noopener noreferrer">Connect an MCP client</a></li>
<li><a href="https://www.devglobe.dev/openapi.json" target="_blank" rel="noopener noreferrer">Read the OpenAPI description</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=devglobedev.devglobe-developer-discovery" target="_blank" rel="noopener noreferrer">Install the VS Code extension</a></li>
</ul>]]></content:encoded>
            <category>devglobe</category>
            <category>azure-cosmos-db</category>
            <category>ai-agents</category>
            <category>mcp</category>
            <category>vector-search</category>
            <category>developer-tools</category>
            <category>open-source</category>
            <category>architecture</category>
        </item>
        <item>
            <title><![CDATA[Two Cities, Two Talks, One Agent-First Future: Bengaluru and Chennai]]></title>
            <link>https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026</link>
            <guid>https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026</guid>
            <pubDate>Thu, 01 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Reflections from two back-to-back community conferences in Bengaluru and Chennai, where I spoke about trusted MCP tools and agent-first development with Azure Cosmos DB.]]></description>
            <content:encoded><![CDATA[<p>The final weekend of September took me to two cities, two developer communities, and two stages with a shared question:</p>
<p><strong>What does it take to move AI agents from impressive demos to experiences developers can trust every day?</strong></p>
<p>On September 26, I spoke at <a href="https://globalai.community/e/bd1o37ln" target="_blank" rel="noopener noreferrer">MCP Community Connect in Bengaluru</a> about designing MCP tools around trust and consent. The next day, I joined the <a href="https://globalai.community/e/7f851feb" target="_blank" rel="noopener noreferrer">Global AI Conference in Chennai</a> to share how we can build an agent-first experience for Azure Cosmos DB.</p>
<p>The talks approached the question from different directions, but they arrived at the same conclusion: an agent is only as useful as the context, boundaries, and developer experience we build around it.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="stop-one-mcp-community-connect-bengaluru">Stop one: MCP Community Connect, Bengaluru<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#stop-one-mcp-community-connect-bengaluru" class="hash-link" aria-label="Direct link to Stop one: MCP Community Connect, Bengaluru" title="Direct link to Stop one: MCP Community Connect, Bengaluru">​</a></h2>
<p>MCP Community Connect was a full-day, community-run conference focused on taking the Model Context Protocol beyond experiments. The agenda went deep into production concerns: security, observability, governance, interoperability, and architecture.</p>
<p>My session, <strong>"Beyond CRUD: Designing MCP Tools Around Trust and Consent,"</strong> focused on a lesson I learned while building <a href="https://devglobe.dev/" target="_blank" rel="noopener noreferrer">DevGlobe</a>: exposing data through MCP is relatively easy. Deciding what an agent should be allowed to discover, infer, and do is the real design challenge.</p>
<p><img decoding="async" loading="lazy" alt="Presenting Beyond CRUD at MCP Community Connect in Bengaluru" src="https://www.sajeetharan.dev/assets/images/beyond-crud-mcp-trust-consent-332e0a006ead63ca283584c2add0fe02.jpg" width="1366" height="768" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-a-generic-database-tool-was-the-wrong-abstraction">Why a generic database tool was the wrong abstraction<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#why-a-generic-database-tool-was-the-wrong-abstraction" class="hash-link" aria-label="Direct link to Why a generic database tool was the wrong abstraction" title="Direct link to Why a generic database tool was the wrong abstraction">​</a></h3>
<p>When we first think about connecting an agent to a database, the obvious approach is to expose familiar operations: query, create, update, and delete. That interface is flexible, but it also transfers too much responsibility to the agent.</p>
<p>DevGlobe is a developer-discovery platform. It works with public professional evidence such as profiles, repositories, languages, locations, and contribution activity. It also supports introductions between people, which is a very different kind of action. Discovery can use public information; initiating contact requires consent.</p>
<p>Instead of exposing a general database interface, I designed domain-specific tools across two trust levels:</p>
<ul>
<li><strong>Anonymous tools</strong> support bounded discovery using public evidence.</li>
<li><strong>Authenticated tools</strong> support consent-controlled introduction workflows.</li>
</ul>
<p>That separation makes the intended behavior clear to both the agent and the developer. More importantly, it turns consent into an application boundary rather than a sentence hidden inside a prompt.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="trust-has-to-exist-in-the-system">Trust has to exist in the system<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#trust-has-to-exist-in-the-system" class="hash-link" aria-label="Direct link to Trust has to exist in the system" title="Direct link to Trust has to exist in the system">​</a></h3>
<p>Prompts are useful guidance, but they are not security boundaries. If an action has consequences for another person, the system must enforce the rules.</p>
<p>For DevGlobe, that means:</p>
<ul>
<li>Returning bounded, structured results rather than unrestricted database access</li>
<li>Including evidence and freshness so the agent does not invent unsupported conclusions</li>
<li>Separating read-only discovery from consequential actions</li>
<li>Requiring authentication before an introduction can be requested</li>
<li>Persisting consent and introduction state as durable application data</li>
<li>Returning explicit errors when a request is unauthorized or invalid</li>
</ul>
<p>The MCP server can remain stateless while coordinating a stateful workflow in Azure Cosmos DB. The agent gets a small, purposeful set of capabilities, and people remain in control of when and how contact happens.</p>
<p>You can explore the full deck here:</p>
<p><a href="https://mcpdeck260726.z13.web.core.windows.net/index.html#1" target="_blank" rel="noopener noreferrer">View the Beyond CRUD slides →</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="stop-two-global-ai-conference-chennai">Stop two: Global AI Conference, Chennai<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#stop-two-global-ai-conference-chennai" class="hash-link" aria-label="Direct link to Stop two: Global AI Conference, Chennai" title="Direct link to Stop two: Global AI Conference, Chennai">​</a></h2>
<p>The following day, I traveled to Chennai for the Global AI Conference, a free one-day gathering for developers, engineers, data professionals, students, and AI builders. The program combined expert sessions, live demos, and hands-on workshops, all focused on turning AI ideas into working systems.</p>
<p>My session was <strong>"Building an Agent-First Experience for Azure Cosmos DB."</strong></p>
<p><img decoding="async" loading="lazy" alt="Presenting Agentic Development with Azure Cosmos DB at the Global AI Conference in Chennai" src="https://www.sajeetharan.dev/assets/images/agent-first-cosmos-db-b30a3cfdaa2f7e0713e43a0bea949cf3.jpg" width="1366" height="768" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-audience-for-developer-guidance-has-changed">The audience for developer guidance has changed<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#the-audience-for-developer-guidance-has-changed" class="hash-link" aria-label="Direct link to The audience for developer guidance has changed" title="Direct link to The audience for developer guidance has changed">​</a></h3>
<p>Documentation used to be written primarily for people. Today, agents retrieve documentation, samples, schemas, and repository context before they generate code or recommend an implementation.</p>
<p>That changes the responsibility of developer platforms:</p>
<ul>
<li><strong>Agents read more of the documentation.</strong> Information must be structured, current, and easy to retrieve.</li>
<li><strong>Agents make more implementation decisions.</strong> API choices, data models, query shapes, retries, and indexing strategies may be selected before a person reviews the result.</li>
<li><strong>Every mistake is amplified.</strong> Weak guidance can become repeated code across projects, while strong guidance makes the preferred path repeatable.</li>
</ul>
<p>Documentation is no longer only content that people read. It is context that agents use to make decisions and write code.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-an-agent-first-database-experience-needs">What an agent-first database experience needs<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#what-an-agent-first-database-experience-needs" class="hash-link" aria-label="Direct link to What an agent-first database experience needs" title="Direct link to What an agent-first database experience needs">​</a></h3>
<p>An agent-first experience is not a chat box placed in front of an existing product. It requires the product to expose the right context and capabilities in forms an agent can use safely.</p>
<p>For Azure Cosmos DB, that experience brings several pieces together:</p>
<ol>
<li><strong>MCP tools</strong> give agents bounded access to real database capabilities.</li>
<li><strong>Skills</strong> encode domain guidance for data modeling, querying, indexing, and SDK usage.</li>
<li><strong>Schema and repository context</strong> help agents understand the application they are changing.</li>
<li><strong>CLI workflows</strong> allow agents to invoke existing tools, inspect results, and adapt.</li>
<li><strong>Human control</strong> keeps consequential operations visible and reviewable.</li>
</ol>
<p>The goal is not to remove the developer. It is to reduce the context switching that gets between a developer and the problem they are trying to solve.</p>
<p>You can view the Chennai session deck here:</p>
<p><a href="https://devglobeactivityfn.z13.web.core.windows.net/talks/agent-first-cosmos-db#1" target="_blank" rel="noopener noreferrer">View the Agentic Development with Azure Cosmos DB slides →</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-connected-both-talks">What connected both talks<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#what-connected-both-talks" class="hash-link" aria-label="Direct link to What connected both talks" title="Direct link to What connected both talks">​</a></h2>
<p>Bengaluru was about <strong>boundaries</strong>. Chennai was about <strong>context</strong>.</p>
<p>An agent needs both.</p>
<p>Context without boundaries creates a capable system that people cannot safely trust. Boundaries without useful context create a safe system that cannot do meaningful work. Good agent experiences combine:</p>
<ul>
<li>The right information</li>
<li>Purpose-built tools</li>
<li>Clear trust levels</li>
<li>Durable application state</li>
<li>Observable actions</li>
<li>Human approval where consequences matter</li>
</ul>
<p>This is the product and engineering work behind agent-first development. The protocol is important, but the experience is shaped by the decisions around it.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="community-makes-the-ideas-better">Community makes the ideas better<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#community-makes-the-ideas-better" class="hash-link" aria-label="Direct link to Community makes the ideas better" title="Direct link to Community makes the ideas better">​</a></h2>
<p>Speaking in Bengaluru and Chennai on consecutive days was a reminder of why local developer communities matter. A slide deck can explain an architecture, but conversations with builders reveal the questions that architecture must answer in the real world.</p>
<p>How much access is too much? Where should consent live? How do teams keep agent guidance current? What should be observable? Which actions should always require a person?</p>
<p>Those questions are not side topics. They are the work.</p>
<p>Thank you to the organizers, volunteers, speakers, and attendees at MCP Community Connect Bengaluru and the Global AI Conference Chennai for creating spaces where developers could examine these challenges together.</p>
<p>The agent-first future will not be built by agents alone. It will be built by communities of people deciding, deliberately, what agents should be able to do—and what must always remain in human hands.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://www.sajeetharan.dev/blogs/global-ai-conference-chennai-bengaluru-2026#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<ul>
<li><a href="https://globalai.community/e/bd1o37ln" target="_blank" rel="noopener noreferrer">MCP Community Connect Bengaluru</a></li>
<li><a href="https://globalai.community/e/7f851feb" target="_blank" rel="noopener noreferrer">Global AI Conference Chennai</a></li>
<li><a href="https://mcpdeck260726.z13.web.core.windows.net/index.html#1" target="_blank" rel="noopener noreferrer">Beyond CRUD slides</a></li>
<li><a href="https://devglobeactivityfn.z13.web.core.windows.net/talks/agent-first-cosmos-db#1" target="_blank" rel="noopener noreferrer">Agentic Development with Azure Cosmos DB slides</a></li>
<li><a href="https://devglobe.dev/" target="_blank" rel="noopener noreferrer">DevGlobe</a></li>
</ul>]]></content:encoded>
            <category>ai</category>
            <category>ai-agents</category>
            <category>mcp</category>
            <category>azure-cosmos-db</category>
            <category>developer-tools</category>
            <category>devglobe</category>
            <category>conference</category>
            <category>community</category>
        </item>
        <item>
            <title><![CDATA[The Regression Tax: Why Your Agent Skills Might Be Breaking More Than They Fix]]></title>
            <link>https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt</link>
            <guid>https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt</guid>
            <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Are agent skills always worth using? A new paper reveals that regressions offset 59% of gross gains — and the best skills win by breaking less, not helping more.]]></description>
            <content:encoded><![CDATA[<p>I've spent the last six months writing skills for AI coding agents. Somewhere around month three, I started noticing something uncomfortable: some of our best-intentioned guidance was making things worse. Not on every task — just on enough tasks to make me question whether we were actually helping.</p>
<p>I couldn't prove it. I had gut feelings and a few suspicious eval runs, but nothing concrete enough to point at and say "this is why."</p>
<p>Then I read <a href="https://arxiv.org/abs/2607.22520" target="_blank" rel="noopener noreferrer">this paper</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-paper-that-put-numbers-on-the-feeling">The paper that put numbers on the feeling<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#the-paper-that-put-numbers-on-the-feeling" class="hash-link" aria-label="Direct link to The paper that put numbers on the feeling" title="Direct link to The paper that put numbers on the feeling">​</a></h2>
<p><em>The Regression Tax: Decomposing Why Skills Help — and Hurt — LLM Agents</em> by Darshan Tank and Baran Nama (Sentient Labs) does something deceptively simple. They ran the same agent on the same tasks with and without skills — nearly 6,000 paired runs across two office-automation benchmarks and three different model–harness stacks (OpenCode + MiniMax-M2.7, Codex + GPT-5.4-mini, Claude Code + Sonnet 4.6).</p>
<p>Then instead of just reporting "skills improved pass rate by X%," they counted both sides: how many tasks did skills <em>fix</em>, and how many tasks did skills <em>break</em>.</p>
<p>The answer stung.</p>
<p>Across all conditions, <strong>regressions wiped out 59% of the gains</strong>. 553 tasks newly solved, 324 tasks newly broken. Net: 229.</p>
<p>That's not a rounding error. That's a tax.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="breaking-less-matters-more-than-helping-more">Breaking less matters more than helping more<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#breaking-less-matters-more-than-helping-more" class="hash-link" aria-label="Direct link to Breaking less matters more than helping more" title="Direct link to Breaking less matters more than helping more">​</a></h2>
<p>Here's the finding that genuinely changed how I think about this work.</p>
<p>The best-performing skill libraries didn't get there by helping on dramatically more tasks. They got there by <strong>breaking fewer things</strong>. The separation between good and bad libraries was mostly on the regression side, not the gain side.</p>
<p>One example from the paper stuck with me. On Claude Code + Sonnet 4.6, three skill libraries gained 10, 11, and 12 tasks respectively on OfficeQA-Pro. Sounds like the 12-gain library wins, right? But they regressed 2, 4, and 7. The library that gained the <em>fewest</em> tasks actually had the best net effect because it barely broke anything.</p>
<p>I thought back to our own work. When we cut the Cosmos DB skill from 2,000 lines down to ~400, the eval numbers went up. At the time I assumed it was because the trimmed version was more focused and helped more. Now I think the real story is simpler: we stopped breaking cases the model already handled. The trim removed more damage than it removed help.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-skills-break-things">How skills break things<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#how-skills-break-things" class="hash-link" aria-label="Direct link to How skills break things" title="Direct link to How skills break things">​</a></h2>
<p>The paper names three mechanisms, and honestly, I've hit all three without knowing what to call them.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="skills-change-behavior-just-by-existing-in-context">Skills change behavior just by existing in context<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#skills-change-behavior-just-by-existing-in-context" class="hash-link" aria-label="Direct link to Skills change behavior just by existing in context" title="Direct link to Skills change behavior just by existing in context">​</a></h3>
<p>They call this "skill-description osmosis." A skill sits in the system prompt — its name, its short description — on every single step. The body never loads. The skill is never invoked. And yet outcomes change.</p>
<p>They showed one task where all three independently written skill libraries caused the exact same wrong answer. None were invoked. The descriptions alone shifted how the agent interpreted a financial figure. Same wrong number, three decimal places, across all three libraries. That's not noise.</p>
<p>I've seen a version of this myself. We had a skill with "structured references" in its description, and it was causing the agent to reach for Excel table-reference syntax on completely unrelated spreadsheet tasks. The skill was never triggered — it was just... there, biasing things.</p>
<p>The scary part: any system that decides whether to suppress a skill based on whether it gets <em>called</em> cannot catch this. The description is always present.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="generic-procedures-override-correct-intuition">Generic procedures override correct intuition<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#generic-procedures-override-correct-intuition" class="hash-link" aria-label="Direct link to Generic procedures override correct intuition" title="Direct link to Generic procedures override correct intuition">​</a></h3>
<p>"Grounding displacement" — a skill tells the agent how to navigate to information, and that procedure sends it to the wrong place. The bare agent would have found the right table on its own. The skill's general-purpose navigation steps redirected it.</p>
<p>This accounted for 59 out of 81 regressions on one benchmark. The most common way skills break things is by overriding a correct reading with a generic one.</p>
<p>Think about it: you write a skill that says "always start by checking the summary table." Great advice most of the time. But for the task where the answer is in a footnote on page 7, you just sent the agent on a detour it never comes back from.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="skills-suppress-the-agents-own-sanity-checks">Skills suppress the agent's own sanity checks<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#skills-suppress-the-agents-own-sanity-checks" class="hash-link" aria-label="Direct link to Skills suppress the agent's own sanity checks" title="Direct link to Skills suppress the agent's own sanity checks">​</a></h3>
<p>"Verification displacement." The skill's procedure takes over, and somewhere along the way the agent stops doing the final "does this answer actually make sense?" check it would have done on its own.</p>
<p>On SpreadsheetBench, 226 out of 663 formula failures were formulas that were <strong>already correct</strong>. The agent wrote the right formula. It just never verified the output. When the researchers re-graded those with a proper execution check, they all passed.</p>
<p>The agent did the hard work. The skill displaced the easy part — looking at what it produced and asking "is this right?"</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-pipeline-problem">The pipeline problem<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#the-pipeline-problem" class="hash-link" aria-label="Direct link to The pipeline problem" title="Direct link to The pipeline problem">​</a></h2>
<p>The paper frames it with a simple diagram that I keep coming back to:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">INPUT → [grounding] → [method/reasoning] → [verification] → OUTPUT</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Skills live almost entirely in the middle box — they're procedural, they tell the agent <em>how</em> to do the work. But when the researchers traced where failures actually happen, procedure was the stage <em>least</em> responsible. Grounding (did the agent read the right input?) and verification (did it check its output?) are where things go wrong.</p>
<p>We're over-engineering the part models are already decent at, and ignoring the parts where they actually need help.</p>
<p>Looking back at our own skill iterations, this tracks. The changes that moved our eval numbers the most weren't better procedures. They were things like "read the partition key path from container settings <em>before</em> writing any query" (grounding) and "after generating output, verify the partition key appears in the WHERE clause" (verification). Boring, specific, and effective.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-im-changing">What I'm changing<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#what-im-changing" class="hash-link" aria-label="Direct link to What I'm changing" title="Direct link to What I'm changing">​</a></h2>
<p>I'm not going to pretend I have this all figured out. But a few things are different now:</p>
<p><strong>We track regressions separately.</strong> Not just "did pass rate go up?" but "which previously-passing tasks now fail?" Two skills with identical net improvement can have completely different regression profiles, and we want the one that breaks less.</p>
<p><strong>Descriptions get the same scrutiny as bodies.</strong> Every word in a skill description is always-on context. It's not just a trigger condition — it's shaping agent behavior on every task, including the ones it has nothing to do with. We're rewriting descriptions to be narrower and more precise, with explicit "DO NOT USE FOR" boundaries.</p>
<p><strong>Less procedure, more anchoring.</strong> Instead of 15-step how-to guides, we're writing short grounding statements ("the data you need is here, not there") and verification checks ("confirm your output satisfies X before returning"). The model knows how to write a Cosmos DB query. It sometimes looks at the wrong container or forgets to check its results.</p>
<p><strong>We test the description-only condition.</strong> Descriptions present, bodies disabled. If outcomes shift, the description is doing unsupervised work. Sometimes that's fine. Sometimes it's osmosis you need to fix.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-uncomfortable-takeaway">The uncomfortable takeaway<a href="https://www.sajeetharan.dev/blogs/the-regression-tax-when-agent-skills-hurt#the-uncomfortable-takeaway" class="hash-link" aria-label="Direct link to The uncomfortable takeaway" title="Direct link to The uncomfortable takeaway">​</a></h2>
<p>I've written before about <a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents">how less is more with skills</a>. This paper makes me think I didn't go far enough.</p>
<p>The instinct when a skill helps on 10 tasks is to celebrate. But if it also silently breaks 7 tasks the bare model had already nailed, your net is 3. And you won't know that unless you're measuring both sides.</p>
<p>Most of the value in skill engineering isn't in the knowledge you add. It's in the damage you don't do. That's the regression tax, and it's higher than any of us assumed.</p>
<hr>
<p><em>Paper: <a href="https://arxiv.org/abs/2607.22520" target="_blank" rel="noopener noreferrer">The Regression Tax: Decomposing Why Skills Help — and Hurt — LLM Agents</a> (Tank &amp; Nama, 2026). If you're building agent skills, read this one.</em></p>]]></content:encoded>
            <category>ai</category>
            <category>coding-agents</category>
            <category>skills</category>
            <category>evaluation</category>
            <category>research</category>
            <category>developer-tools</category>
        </item>
        <item>
            <title><![CDATA[Smart Prompting, Stronger AI Agent Outcomes — What Actually Works]]></title>
            <link>https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes</link>
            <guid>https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes</guid>
            <pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Over the past few months, one prompting pattern has consistently produced better AI agents for me. Not bigger prompts. Not more skills. Just a better separation of responsibilities.]]></description>
            <content:encoded><![CDATA[<p>Over the past few months, one prompting pattern has consistently produced better AI agents for me.</p>
<p>Not bigger prompts.</p>
<p>Not more skills.</p>
<p>Just a better separation of responsibilities.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-framework">The Framework<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#the-framework" class="hash-link" aria-label="Direct link to The Framework" title="Direct link to The Framework">​</a></h2>
<p>My current approach boils down to three pillars:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="-lean-prompts">✅ Lean Prompts<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#-lean-prompts" class="hash-link" aria-label="Direct link to ✅ Lean Prompts" title="Direct link to ✅ Lean Prompts">​</a></h3>
<p>Tell the agent <strong>what</strong> to do, not <strong>how</strong> to do everything.</p>
<ul>
<li>Be clear about the goal</li>
<li>Include only what's essential</li>
<li>Avoid fluff and unnecessary details</li>
</ul>
<p>Instead of writing a 500-line prompt that tries to cover every edge case, I keep it short:</p>
<blockquote>
<p><em>"List the top 5 features of our product."</em></p>
</blockquote>
<p>That's it. No preamble. No over-explanation. The agent doesn't need a backstory.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="-rich-artifacts--context">📚 Rich Artifacts &amp; Context<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#-rich-artifacts--context" class="hash-link" aria-label="Direct link to 📚 Rich Artifacts &amp; Context" title="Direct link to 📚 Rich Artifacts &amp; Context">​</a></h3>
<p>Put the heavy lifting into documentation, examples, schemas, and project knowledge — not the prompt itself.</p>
<ul>
<li>Add docs, schemas, references</li>
<li>Share examples and constraints</li>
<li>Include relevant project knowledge</li>
</ul>
<p>This is where files like <code>architecture.md</code>, <code>schema.json</code>, <code>coding-standards.md</code>, and <code>examples/</code> come in. The agent reads these as context, so your prompt stays lean while the agent still has everything it needs.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="-small-focused-skills">🧩 Small, Focused Skills<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#-small-focused-skills" class="hash-link" aria-label="Direct link to 🧩 Small, Focused Skills" title="Direct link to 🧩 Small, Focused Skills">​</a></h3>
<p>Keep skills modular with a single responsibility instead of building giant "do everything" tools.</p>
<ul>
<li>Single purpose</li>
<li>Modular and composable</li>
<li>Easy to maintain and extend</li>
</ul>
<p>Think <code>query-data</code>, <code>run-tests</code>, <code>generate-report</code>, <code>create-pr</code> — each skill does one thing well. Not a monolithic "handle-everything" skill that tries to be clever.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-this-works">Why This Works<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#why-this-works" class="hash-link" aria-label="Direct link to Why This Works" title="Direct link to Why This Works">​</a></h2>
<p>The result of applying this pattern consistently:</p>
<ul>
<li><strong>More consistent outputs</strong> — The agent isn't distracted by irrelevant instructions</li>
<li><strong>Better reasoning</strong> — Smaller context means the agent focuses on what matters</li>
<li><strong>Easier maintenance</strong> — Change one skill without breaking everything else</li>
<li><strong>Lower token usage</strong> — Less prompt bloat means faster, cheaper responses</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-i-learned-building-this-in-practice">What I Learned Building This in Practice<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#what-i-learned-building-this-in-practice" class="hash-link" aria-label="Direct link to What I Learned Building This in Practice" title="Direct link to What I Learned Building This in Practice">​</a></h2>
<p>This isn't theoretical. I arrived at this framework through months of hands-on work building AI agent skills and tools. Here are some concrete examples from my own experience:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="building-the-cosmos-db-best-practices-skill">Building the Cosmos DB Best Practices Skill<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#building-the-cosmos-db-best-practices-skill" class="hash-link" aria-label="Direct link to Building the Cosmos DB Best Practices Skill" title="Direct link to Building the Cosmos DB Best Practices Skill">​</a></h3>
<p>When I started building skills for the <a href="https://github.com/AzureCosmosDB/cosmosdb-agent-kit" target="_blank" rel="noopener noreferrer">Azure Cosmos DB Agent Kit</a>, I fell into the <strong>"more is better" trap</strong>. We wrote down everything — partition key strategies, indexing decisions, query optimization, change feed patterns, vector search setup. The skill file kept growing past 2,000 lines.</p>
<p>Then we started measuring. Some of that guidance made <strong>zero measurable difference</strong> — the model already knew it from training data. A few cases actually made things <strong>worse</strong> because the model spent attention budget processing our instructions instead of solving the problem.</p>
<p>The fix? We trimmed to a ~400-line core backed by reference files that load on-demand. Performance improved. Token usage dropped by ~60%. The lesson: <strong>skills matter most where the model's training data is thin.</strong></p>
<p>I wrote about this journey in depth in my post <a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents">What Six Months of Building AI Agent Skills Taught Me About Writing for Machines</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-skills-for-real-customer-scenarios">Using Skills for Real Customer Scenarios<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#using-skills-for-real-customer-scenarios" class="hash-link" aria-label="Direct link to Using Skills for Real Customer Scenarios" title="Direct link to Using Skills for Real Customer Scenarios">​</a></h3>
<p>The framework proved itself in real support scenarios. When a customer needed help understanding why they couldn't scale down their Cosmos DB autoscale throughput after a test, I used the best practices skill to quickly generate accurate, context-aware guidance. The skill provided the precise domain knowledge the agent needed — not a generic explanation, but the exact autoscale behavior rules. Lean prompt + rich context = accurate answer in seconds.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="extending-skills-for-customer-specific-scenarios">Extending Skills for Customer-Specific Scenarios<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#extending-skills-for-customer-specific-scenarios" class="hash-link" aria-label="Direct link to Extending Skills for Customer-Specific Scenarios" title="Direct link to Extending Skills for Customer-Specific Scenarios">​</a></h3>
<p>Enterprise customers like Walmart and Nike started asking for customized skills tailored to their specific use cases. This validated the modular approach — because each skill had a single responsibility, we could extend or compose them for customer scenarios without rewriting the core. A monolithic skill would have made this nearly impossible.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="skill-descriptions-are-underrated">Skill Descriptions Are Underrated<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#skill-descriptions-are-underrated" class="hash-link" aria-label="Direct link to Skill Descriptions Are Underrated" title="Direct link to Skill Descriptions Are Underrated">​</a></h3>
<p>One of the subtler lessons: <strong>how you describe a skill matters as much as what's in it.</strong> Our first skill description was vague — "Best practices for Cosmos DB." It got triggered for everything remotely related, including completely wrong contexts.</p>
<p>The fix was adding explicit scope boundaries and <strong>negative triggers</strong>. A good description says what the skill is for <em>and</em> what it's not for. "Do NOT use for MongoDB, PostgreSQL, or DynamoDB" is surprisingly effective at preventing false matches. We also found that skill registries degrade in selection accuracy past ~20-30 entries without a retrieval filter.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-anti-pattern-why-long-prompts-fail">The Anti-Pattern: Why Long Prompts Fail<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#the-anti-pattern-why-long-prompts-fail" class="hash-link" aria-label="Direct link to The Anti-Pattern: Why Long Prompts Fail" title="Direct link to The Anti-Pattern: Why Long Prompts Fail">​</a></h2>
<p>I've seen (and written) the opposite approach — massive prompts that try to anticipate every scenario. They fail for predictable reasons:</p>
<ol>
<li>
<p><strong>Context rot</strong> — Even models with 200K token windows lose attention in the middle. <a href="https://trychroma.com/research/context-rot" target="_blank" rel="noopener noreferrer">Research confirms this</a>. A big context window is not the same as a big <em>useful</em> context window.</p>
</li>
<li>
<p><strong>Diminishing returns</strong> — Past ~800 lines, performance degrades regardless of model. More tokens ≠ better output.</p>
</li>
<li>
<p><strong>Maintenance nightmare</strong> — One giant prompt means every change risks breaking something else. Small skills are independently testable and updatable.</p>
</li>
<li>
<p><strong>Duplicating training data</strong> — Frontier models already know common patterns. Writing skills for things models already handle is wasted effort.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-get-started">How to Get Started<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#how-to-get-started" class="hash-link" aria-label="Direct link to How to Get Started" title="Direct link to How to Get Started">​</a></h2>
<p>If you want to try this framework:</p>
<ol>
<li>
<p><strong>Audit your prompts</strong> — Find the ones that are doing too much. Split the "what to do" from the "how to do it."</p>
</li>
<li>
<p><strong>Extract context into files</strong> — Move schemas, examples, coding standards, and domain knowledge into separate artifacts the agent can reference.</p>
</li>
<li>
<p><strong>Build small skills</strong> — One skill per capability. If a skill description needs the word "and," it's probably two skills.</p>
</li>
<li>
<p><strong>Measure</strong> — Even a crude evaluation (5 test cases, 3 trials each) is infinitely better than vibes. You'll be surprised what the model already knows.</p>
</li>
<li>
<p><strong>Iterate</strong> — Treat skills like code. Test them. Version them. Cut what doesn't help.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="whats-your-prompting-philosophy">What's Your Prompting Philosophy?<a href="https://www.sajeetharan.dev/blogs/2026/07/16/2026/07/smart-prompting-stronger-ai-agent-outcomes#whats-your-prompting-philosophy" class="hash-link" aria-label="Direct link to What's Your Prompting Philosophy?" title="Direct link to What's Your Prompting Philosophy?">​</a></h2>
<p>I'm curious if others have arrived at the same conclusion.</p>
<ul>
<li>Do you rely on long prompts?</li>
<li>Do you invest more in context?</li>
<li>Or have you found another approach that works even better?</li>
</ul>
<p>Share your tips, prompts, or real-world examples — let's learn from each other.</p>]]></content:encoded>
            <category>ai</category>
            <category>coding-agents</category>
            <category>prompting</category>
            <category>skills</category>
            <category>developer-tools</category>
            <category>github-copilot</category>
            <category>microsoft</category>
        </item>
        <item>
            <title><![CDATA[What Six Months of Building AI Agent Skills Taught Me About Writing for Machines]]></title>
            <link>https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents</link>
            <guid>https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents</guid>
            <pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Back in January, I started building skills for AI coding agents — domain-specific guidance that helps agents like GitHub Copilot, Claude, and others produce...]]></description>
            <content:encoded><![CDATA[<p>Back in January, I started building skills for AI coding agents — domain-specific guidance that helps agents like GitHub Copilot, Claude, and others produce better code in areas they'd otherwise struggle with. My domain happened to be Azure Cosmos DB, but the lessons apply to anyone writing skills for any technology.</p>
<p>Six months later, what I learned about <em>how</em> to write for AI agents turned out to be far more interesting than the domain knowledge itself.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-starting-point">The starting point<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#the-starting-point" class="hash-link" aria-label="Direct link to The starting point" title="Direct link to The starting point">​</a></h2>
<p>The idea seemed simple enough: take deep expertise in a technology, write it down as structured guidance, and feed it to coding agents as a "skill." The agent reads the skill, follows the rules, and produces better output. Easy.</p>
<p>So that's what we did. We wrote down everything — design patterns, common pitfalls, configuration recipes, SDK best practices, operational guidance. For Cosmos DB specifically, this meant partition key strategies, indexing decisions, query optimization, change feed patterns, vector search setup. Hundreds of rules, all carefully documented.</p>
<p>It felt productive. We were <em>capturing knowledge</em>. Surely more knowledge = better outcomes?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-more-is-better-trap">The "more is better" trap<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#the-more-is-better-trap" class="hash-link" aria-label="Direct link to The &quot;more is better&quot; trap" title="Direct link to The &quot;more is better&quot; trap">​</a></h2>
<p>We kept adding. Every edge case, every teammate's favorite gotcha, every "oh you should also mention..." went in. The skill file kept growing — 500 lines, 1000, eventually past 2000.</p>
<p>Then newer models came out — and they were already pretty good at a lot of what we'd written. Without any skill at all, they'd handle basic scenarios correctly. They already knew common patterns from training data.</p>
<p>Which raised the uncomfortable question: <strong>were our skills actually helping, or were we just duplicating what models already knew?</strong></p>
<p>We had no idea. We were operating on vibes.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="we-started-measuring-and-got-humbled">We started measuring (and got humbled)<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#we-started-measuring-and-got-humbled" class="hash-link" aria-label="Direct link to We started measuring (and got humbled)" title="Direct link to We started measuring (and got humbled)">​</a></h2>
<p>This is where things got real. We set up controlled experiments — give the same coding tasks to agents with and without our skills, then grade the output systematically.</p>
<p>We tested:</p>
<ul>
<li>Bare model, zero guidance</li>
<li>Full monolithic skill (everything we'd written)</li>
<li>Trimmed versions (cut the obvious stuff)</li>
<li>Split by topic (separate skills per domain area)</li>
<li>Across different foundation models</li>
<li>Across different agent runtimes</li>
</ul>
<p>Some results stung. There were scenarios where our carefully written guidance made <em>zero measurable difference</em>. A few cases where it actually made things <em>worse</em> — the model spent attention budget processing our instructions instead of just solving the problem.</p>
<p>But there were also clear wins. Complex, nuanced scenarios — things where even frontier models would make mistakes — showed real improvement with skills. The pattern was clear: <strong>skills matter most where the model's training data is thin or the task requires precise, multi-step domain reasoning.</strong></p>
<p>For Cosmos DB, that meant skills were invaluable for things like multi-container data modeling and vector search configuration, but unnecessary for basic CRUD operations or simple queries.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-split-skills-experiment-and-why-it-mostly-didnt-help">The split skills experiment (and why it mostly didn't help)<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#the-split-skills-experiment-and-why-it-mostly-didnt-help" class="hash-link" aria-label="Direct link to The split skills experiment (and why it mostly didn't help)" title="Direct link to The split skills experiment (and why it mostly didn't help)">​</a></h2>
<p>We had a theory: break the monolith into smaller, topic-focused skills. One for data modeling. One for querying. One for SDK patterns. Clean separation.</p>
<p>Sounded great. In practice? The agent loaded three of them for a single task, ending up with roughly the same token count as the monolith. Different filing cabinet, same pile of paper on the desk.</p>
<p>The lesson: <strong>splitting only helps if it changes what actually gets loaded per interaction.</strong> Reorganizing files doesn't reduce context consumption. You need a mechanism that selectively loads only what's relevant for the current task.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="context-rot-is-real">Context rot is real<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#context-rot-is-real" class="hash-link" aria-label="Direct link to Context rot is real" title="Direct link to Context rot is real">​</a></h2>
<p>Here's something that caught me off guard. A skill that worked beautifully on one model (long context window) completely fell apart on another (tighter window). Same content, wildly different results.</p>
<p>There's <a href="https://trychroma.com/research/context-rot" target="_blank" rel="noopener noreferrer">research on this phenomenon</a> — even if a model technically supports 200K tokens, its actual attention degrades well before that limit. Information in the middle gets lost. Instructions at the end carry less weight. A big context window is not the same as a big <em>useful</em> context window.</p>
<p>The takeaway: <strong>how you package guidance matters as much as what's in it.</strong> Skill design isn't just a content problem — it's a delivery problem.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="five-principles-that-actually-work">Five principles that actually work<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#five-principles-that-actually-work" class="hash-link" aria-label="Direct link to Five principles that actually work" title="Direct link to Five principles that actually work">​</a></h2>
<p>After months of experimentation, five things consistently improved skill effectiveness regardless of the domain:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-steps-beat-prose-every-time">1. Steps beat prose, every time<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#1-steps-beat-prose-every-time" class="hash-link" aria-label="Direct link to 1. Steps beat prose, every time" title="Direct link to 1. Steps beat prose, every time">​</a></h3>
<p>Our early skills read like documentation — conversational, nuanced, full of "it depends." Models hated it. They'd cherry-pick fragments or hallucinate steps that weren't there.</p>
<p>Rewriting as numbered, deterministic procedures changed everything. For example, instead of <em>"Consider your access patterns and choose appropriately..."</em>, we'd write:</p>
<ol>
<li>Identify the most frequent query predicate</li>
<li>Check candidate cardinality (must exceed threshold)</li>
<li>Validate with a concrete query</li>
<li>If below threshold, combine fields into a composite</li>
</ol>
<p>No ambiguity. No interpretation needed. Pass rates improved immediately across every domain we tested.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-how-you-describe-the-skill-matters-more-than-you-think">2. How you describe the skill matters more than you think<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#2-how-you-describe-the-skill-matters-more-than-you-think" class="hash-link" aria-label="Direct link to 2. How you describe the skill matters more than you think" title="Direct link to 2. How you describe the skill matters more than you think">​</a></h3>
<p>Our first skill description was vague — something like "Best practices for [Technology X]." It got triggered for everything remotely related, including completely wrong contexts.</p>
<p>The fix: explicit scope boundaries and <strong>negative triggers</strong>. A good description says what the skill is for <em>and</em> what it's not for. "Do NOT use for [related but different technology]" is surprisingly effective at preventing false matches.</p>
<p>We also found that skill registries degrade in selection accuracy past ~20-30 entries without a retrieval filter. Precise descriptions become doubly important as your skill library grows.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-dont-front-load-everything">3. Don't front-load everything<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#3-dont-front-load-everything" class="hash-link" aria-label="Direct link to 3. Don't front-load everything" title="Direct link to 3. Don't front-load everything">​</a></h3>
<p>We went from 2000+ lines to a ~400-line core backed by reference files that load on-demand. The core says <em>"For [specific topic], read <code>references/topic-details.md</code>"</em> — and the agent only pulls that in when the task requires it.</p>
<p>Our empirical finding: performance degrades above ~800 lines regardless of model. Keep the entry point lean. Defer supplementary detail to separate files that get loaded only when explicitly needed.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-scripts-over-step-by-step-instructions">4. Scripts over step-by-step instructions<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#4-scripts-over-step-by-step-instructions" class="hash-link" aria-label="Direct link to 4. Scripts over step-by-step instructions" title="Direct link to 4. Scripts over step-by-step instructions">​</a></h3>
<p>Any multi-step operation with dependencies between steps (setup flows, migrations, environment configuration) should be wrapped in a single executable script. Models routinely skip steps, reorder operations, or miss conditional branches when given sequential instructions.</p>
<p>One script call = deterministic execution = no ambiguity. We apply this everywhere a task involves more than two sequential commands with dependencies.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="5-route-dont-concatenate">5. Route, don't concatenate<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#5-route-dont-concatenate" class="hash-link" aria-label="Direct link to 5. Route, don't concatenate" title="Direct link to 5. Route, don't concatenate">​</a></h3>
<p>The real breakthrough: a lightweight "router" skill that examines the task and selectively loads <em>only</em> the relevant sub-skill. A modeling question loads the modeling skill. A performance question loads the optimization skill. Not both.</p>
<p>This cut average context consumption by ~60% with no loss in coverage. The key insight: <strong>composition only works if it changes what gets loaded, not just how files are organized on disk.</strong></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-bigger-lessons">The bigger lessons<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#the-bigger-lessons" class="hash-link" aria-label="Direct link to The bigger lessons" title="Direct link to The bigger lessons">​</a></h2>
<p>Three things I'll carry with me:</p>
<p><strong>Measure before you write.</strong> We would have sworn certain skills were helping. Data said otherwise. Start with evaluation, not authoring. You'll be surprised what models already know — and even more surprised what they consistently get wrong.</p>
<p><strong>Less is more.</strong> Every token competes for attention. A focused 300-line skill covering what the model <em>doesn't already know</em> beats a comprehensive 2000-line one that mostly repeats training data.</p>
<p><strong>This is a new discipline.</strong> Writing for AI agents isn't like writing docs, tutorials, or prompts. It's closer to writing a curriculum for a very fast, very literal student who reads everything once and has limited short-term memory. That mental model changes how you structure everything.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="hill-climbing-continuous-improvement">Hill-climbing: continuous improvement<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#hill-climbing-continuous-improvement" class="hash-link" aria-label="Direct link to Hill-climbing: continuous improvement" title="Direct link to Hill-climbing: continuous improvement">​</a></h2>
<p>We now treat skills like code — they get tested. The loop:</p>
<ol>
<li>Define what success looks like for a set of tasks</li>
<li>Write 10-20 scenarios (including negative cases where the skill should <em>not</em> trigger)</li>
<li>Run 5-30 trials per scenario</li>
<li>Grade with script graders (did the output actually work?) and LLM graders (was the reasoning sound?)</li>
<li>Identify failure patterns, tweak the skill</li>
<li>Re-run and compare</li>
</ol>
<p>Each cycle pushes pass rates up incrementally. It catches regressions when underlying models update. It's tedious, but it's the only way to know if your skills are actually getting better versus just <em>feeling</em> better.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="if-youre-starting-out">If you're starting out<a href="https://www.sajeetharan.dev/blogs/building-skills-for-ai-coding-agents#if-youre-starting-out" class="hash-link" aria-label="Direct link to If you're starting out" title="Direct link to If you're starting out">​</a></h2>
<p>My honest advice for anyone building skills in their own domain:</p>
<ol>
<li><strong>Pick the hard stuff.</strong> Don't write skills for things models already handle. Focus on areas where you see consistent failures or where domain expertise genuinely matters.</li>
<li><strong>Measure from day one.</strong> Even a crude eval (5 test cases, 3 trials each) is infinitely better than vibes.</li>
<li><strong>Write procedures, not explanations.</strong> The agent doesn't need to <em>understand why</em> — it needs to know <em>what to do</em>.</li>
<li><strong>Keep it short.</strong> If you can't fit the core guidance in 400-500 lines, you're probably trying to cover too much in one skill.</li>
<li><strong>Test negative cases.</strong> Make sure your skill doesn't trigger where it shouldn't. False positives are as bad as missing coverage.</li>
</ol>
<p>Minko Gechev gave a <a href="https://mgechev.github.io/skill-design-for-llm-agents-slides/" target="_blank" rel="noopener noreferrer">great talk on skill design</a> at the AI Coding Summit that covers many of these same principles from a framework perspective. Highly recommend it if you're working in this space.</p>
<p>Six months in, I'm more convinced than ever that the hard problem isn't capturing knowledge — it's delivering it effectively to a system with very different attention patterns than a human reader. We're still learning. But the gap between "skills that feel right" and "skills that measurably work" is where all the interesting problems live.</p>]]></content:encoded>
            <category>ai</category>
            <category>coding-agents</category>
            <category>skills</category>
            <category>evaluation</category>
            <category>developer-tools</category>
            <category>microsoft</category>
        </item>
        <item>
            <title><![CDATA[Joining Scott Hanselman on the Azure Developers Show: Turning Coding Agents into a Cosmos DB Expert]]></title>
            <link>https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman</link>
            <guid>https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman</guid>
            <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[I recently had the incredible opportunity to join Scott Hanselman on the Azure Developers Show to talk about something I've been deeply passionate about —...]]></description>
            <content:encoded><![CDATA[<p>I recently had the incredible opportunity to join <strong>Scott Hanselman</strong> on the <a href="https://www.youtube.com/watch?v=GWid8x3i9Cc" target="_blank" rel="noopener noreferrer">Azure Developers Show</a> to talk about something I've been deeply passionate about — <strong>turning coding agents into Azure Cosmos DB experts with the Agent Kit</strong>.</p>
<p>This session was special to me, not just because of the topic, but because of the person I got to share the stage with.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="scott-hanselman-an-inspiration-since-2014">Scott Hanselman: An Inspiration Since 2014<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#scott-hanselman-an-inspiration-since-2014" class="hash-link" aria-label="Direct link to Scott Hanselman: An Inspiration Since 2014" title="Direct link to Scott Hanselman: An Inspiration Since 2014">​</a></h2>
<p>Scott Hanselman has been one of my biggest inspirations in the developer community since <strong>2014</strong>. His ability to break down complex technical topics, his genuine enthusiasm for empowering developers, and his commitment to making technology accessible have always resonated with me. I've followed his blog, podcasts, and talks for over a decade, and his content has shaped how I think about developer experience and community building.</p>
<p>I had the privilege of <strong>meeting Scott in person for the first time in 2018</strong> at the <strong>Microsoft MVP Summit in Seattle</strong>. As a Microsoft MVP, attending the summit was already a dream come true, but getting to meet and interact with Scott made it truly unforgettable. He was exactly as warm, approachable, and passionate in person as he comes across in his content. That encounter reinforced my belief that the best technologists are those who lift others up.</p>
<p>Fast forward to 2026, and here I am, joining him on the Azure Developers Show to demo the work our team has been building. It's one of those full-circle moments that remind you why you keep pushing forward in your career.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-we-covered-in-the-session">What We Covered in the Session<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#what-we-covered-in-the-session" class="hash-link" aria-label="Direct link to What We Covered in the Session" title="Direct link to What We Covered in the Session">​</a></h2>
<p>In the session, we explored how the <strong>Azure Cosmos DB Agent Kit</strong> transforms AI-powered coding agents into database experts. Here's a breakdown of what we discussed:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-problem">The Problem<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#the-problem" class="hash-link" aria-label="Direct link to The Problem" title="Direct link to The Problem">​</a></h3>
<p>Coding agents like GitHub Copilot, Claude, and others are incredibly powerful for general programming tasks, but they often lack deep expertise when it comes to specific database operations, query optimization, and data modeling best practices for Azure Cosmos DB.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-solution-azure-cosmos-db-agent-kit">The Solution: Azure Cosmos DB Agent Kit<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#the-solution-azure-cosmos-db-agent-kit" class="hash-link" aria-label="Direct link to The Solution: Azure Cosmos DB Agent Kit" title="Direct link to The Solution: Azure Cosmos DB Agent Kit">​</a></h3>
<p>The Agent Kit bridges this gap by providing coding agents with:</p>
<ul>
<li><strong>Schema discovery</strong> — Agents can explore your database structure, understand containers, partition keys, and indexing policies</li>
<li><strong>Intelligent CRUD operations</strong> — Context-aware create, read, update, and delete operations that follow Cosmos DB best practices</li>
<li><strong>Query optimization</strong> — AI-assisted query building that respects partition key strategies and minimizes RU consumption</li>
<li><strong>Vector search capabilities</strong> — Enabling agents to perform semantic queries against your data</li>
<li><strong>MCP integration</strong> — Seamless integration through the Model Context Protocol for tool-augmented AI workflows</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="key-takeaways">Key Takeaways<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#key-takeaways" class="hash-link" aria-label="Direct link to Key Takeaways" title="Direct link to Key Takeaways">​</a></h3>
<ol>
<li><strong>Agent-first development</strong> is becoming the norm — developers increasingly rely on AI agents for database interactions</li>
<li><strong>Domain-specific toolkits</strong> like the Agent Kit are essential for agents to provide expert-level guidance</li>
<li><strong>The MCP protocol</strong> enables standardized communication between AI agents and tools, making integrations portable across different AI assistants</li>
<li><strong>Developer experience matters</strong> — The Agent Kit is designed to feel natural within existing development workflows</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="watch-the-full-session">Watch the Full Session<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#watch-the-full-session" class="hash-link" aria-label="Direct link to Watch the Full Session" title="Direct link to Watch the Full Session">​</a></h2>
<p>If you missed the live session, you can watch the full recording here:</p>
<iframe width="100%" height="400" src="https://www.youtube.com/embed/GWid8x3i9Cc" title="Turning Coding Agents into an Azure Cosmos DB Expert with the Agent Kit" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
<p><a href="https://www.youtube.com/watch?v=GWid8x3i9Cc" target="_blank" rel="noopener noreferrer">Watch on YouTube →</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-note-of-gratitude">A Note of Gratitude<a href="https://www.sajeetharan.dev/blogs/2026/07/10/2026/07/turning-coding-agents-cosmosdb-expert-scott-hanselman#a-note-of-gratitude" class="hash-link" aria-label="Direct link to A Note of Gratitude" title="Direct link to A Note of Gratitude">​</a></h2>
<p>Thank you, Scott, for the opportunity and for being such a generous host. And thank you to the <strong>Azure Developers</strong> team for having me on the show. Moments like these fuel my passion for building tools that make developers' lives better.</p>
<p>If you're working with Azure Cosmos DB and want to supercharge your coding agents, check out the <a href="https://github.com/AzureCosmosDB/agent-kit" target="_blank" rel="noopener noreferrer">Azure Cosmos DB Agent Kit</a> and let me know what you think!</p>]]></content:encoded>
            <category>azure-cosmos-db</category>
            <category>ai</category>
            <category>coding-agents</category>
            <category>scott-hanselman</category>
            <category>agent-kit</category>
            <category>developer-tools</category>
            <category>microsoft</category>
        </item>
        <item>
            <title><![CDATA[Introducing Angular Agent Kit - AI-Powered Best Practices for Angular Development]]></title>
            <link>https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit</link>
            <guid>https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit</guid>
            <pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview: I'm excited to announce the release of Angular Agent Kit - a collection of AI coding agent skills designed specifically for Angular developers....]]></description>
            <content:encoded><![CDATA[<p><strong>Overview:</strong></p>
<p>I'm excited to announce the release of <a href="https://github.com/sajeetharan/angular-agent-kit" target="_blank" rel="noopener noreferrer">Angular Agent Kit</a> - a collection of AI coding agent skills designed specifically for Angular developers. This toolkit extends the capabilities of AI coding assistants like GitHub Copilot, Claude Code, Cursor, and Gemini CLI with deep Angular expertise.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-angular-agent-kit">What is Angular Agent Kit?<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#what-is-angular-agent-kit" class="hash-link" aria-label="Direct link to What is Angular Agent Kit?" title="Direct link to What is Angular Agent Kit?">​</a></h2>
<p>Angular Agent Kit is a collection of skills that follow the <a href="https://agentskills.io/" target="_blank" rel="noopener noreferrer">Agent Skills</a> specification. These skills are packaged instructions and scripts that extend AI agent capabilities, enabling them to provide expert-level guidance on Angular development.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-problem-it-solves">The Problem It Solves<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#the-problem-it-solves" class="hash-link" aria-label="Direct link to The Problem It Solves" title="Direct link to The Problem It Solves">​</a></h2>
<p>As Angular applications grow in complexity, maintaining performance becomes increasingly challenging. Developers often struggle with:</p>
<ul>
<li><strong>Change detection optimization</strong> - Understanding when to use OnPush strategy</li>
<li><strong>Bundle size management</strong> - Identifying and eliminating bloat</li>
<li><strong>Template performance</strong> - Writing efficient templates that don't cause unnecessary re-renders</li>
<li><strong>RxJS patterns</strong> - Avoiding memory leaks and implementing efficient async operations</li>
</ul>
<p>While AI coding assistants are powerful, they sometimes lack the specialized Angular knowledge needed to provide optimal recommendations. Angular Agent Kit bridges this gap.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="available-skills">Available Skills<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#available-skills" class="hash-link" aria-label="Direct link to Available Skills" title="Direct link to Available Skills">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="angular-best-practices">angular-best-practices<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#angular-best-practices" class="hash-link" aria-label="Direct link to angular-best-practices" title="Direct link to angular-best-practices">​</a></h3>
<p>The flagship skill contains <strong>45+ rules across 8 categories</strong>, prioritized by their impact on application performance:</p>
<table><thead><tr><th>Category</th><th>Priority</th></tr></thead><tbody><tr><td>Change Detection</td><td>Critical</td></tr><tr><td>Bundle Size Optimization</td><td>Critical</td></tr><tr><td>Template Performance</td><td>High</td></tr><tr><td>RxJS &amp; Async Operations</td><td>High</td></tr><tr><td>Component Architecture</td><td>Medium-High</td></tr><tr><td>HTTP &amp; Data Fetching</td><td>Medium</td></tr><tr><td>Forms &amp; Validation</td><td>Medium</td></tr><tr><td>Testing &amp; Debugging</td><td>Low-Medium</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="installation">Installation<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#installation" class="hash-link" aria-label="Direct link to Installation" title="Direct link to Installation">​</a></h2>
<p>Getting started is simple with a single command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx skills add sajeetharan/angular-agent-kit</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="usage-examples">Usage Examples<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#usage-examples" class="hash-link" aria-label="Direct link to Usage Examples" title="Direct link to Usage Examples">​</a></h2>
<p>Once installed, skills are automatically available. Simply ask your AI assistant:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Review my Angular component for performance issues</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Help me optimize change detection in this component</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Optimize this Angular template for better performance</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The AI agent will automatically leverage the Angular best practices rules to provide expert-level recommendations.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="compatibility">Compatibility<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#compatibility" class="hash-link" aria-label="Direct link to Compatibility" title="Direct link to Compatibility">​</a></h2>
<p>Angular Agent Kit works with all major AI coding tools:</p>
<ul>
<li><strong>GitHub Copilot</strong> - Works seamlessly in VS Code</li>
<li><strong>Claude Code</strong> - Full support for Claude's coding assistant</li>
<li><strong>Cursor</strong> - Enhanced Angular development experience</li>
<li><strong>Gemini CLI</strong> - Google's AI coding assistant</li>
<li>Any other Agent Skills-compatible tools</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="skill-structure">Skill Structure<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#skill-structure" class="hash-link" aria-label="Direct link to Skill Structure" title="Direct link to Skill Structure">​</a></h2>
<p>Each skill in the kit follows a consistent structure:</p>
<ul>
<li><code>SKILL.md</code> - Instructions that trigger skill activation</li>
<li><code>AGENTS.md</code> - Compiled rules that agents read</li>
<li><code>rules/</code> - Individual rule files for easy maintenance</li>
<li><code>metadata.json</code> - Version and metadata information</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-i-built-this">Why I Built This<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#why-i-built-this" class="hash-link" aria-label="Direct link to Why I Built This" title="Direct link to Why I Built This">​</a></h2>
<p>As someone who works extensively with Angular and AI development tools, I noticed a gap between generic AI coding assistance and Angular-specific expertise. The rules in this kit are distilled from years of Angular development experience, official Angular documentation, and community best practices.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="acknowledgments">Acknowledgments<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#acknowledgments" class="hash-link" aria-label="Direct link to Acknowledgments" title="Direct link to Acknowledgments">​</a></h2>
<p>This project was inspired by:</p>
<ul>
<li><a href="https://vercel.com/blog/introducing-react-best-practices" target="_blank" rel="noopener noreferrer">Vercel's React Best Practices</a></li>
<li>The <a href="https://agentskills.io/" target="_blank" rel="noopener noreferrer">Agent Skills</a> specification</li>
<li>Angular team's <a href="https://angular.dev/" target="_blank" rel="noopener noreferrer">official documentation</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="contributing">Contributing<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#contributing" class="hash-link" aria-label="Direct link to Contributing" title="Direct link to Contributing">​</a></h2>
<p>Contributions are welcome! If you have Angular best practices that should be included, or improvements to existing rules, please check out the <a href="https://github.com/sajeetharan/angular-agent-kit/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer">CONTRIBUTING.md</a> file for guidelines.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="get-started-today">Get Started Today<a href="https://www.sajeetharan.dev/blogs/2026/01/30/2026/01/introducing-angular-agent-kit#get-started-today" class="hash-link" aria-label="Direct link to Get Started Today" title="Direct link to Get Started Today">​</a></h2>
<p>Ready to supercharge your Angular development with AI-powered best practices?</p>
<ol>
<li>Install the skill: <code>npx skills add sajeetharan/angular-agent-kit</code></li>
<li>Open your Angular project</li>
<li>Ask your AI assistant for Angular optimization help</li>
</ol>
<p>Check out the <a href="https://github.com/sajeetharan/angular-agent-kit" target="_blank" rel="noopener noreferrer">GitHub repository</a> for more details and to star the project if you find it useful!</p>
<hr>
<p><em>Have questions or feedback? Feel free to open an issue on GitHub or reach out to me on Twitter!</em></p>]]></content:encoded>
            <category>angular</category>
            <category>ai</category>
            <category>agent-skills</category>
            <category>performance</category>
            <category>best-practices</category>
            <category>developer-tools</category>
            <category>github-copilot</category>
            <category>cursor</category>
            <category>claude</category>
        </item>
        <item>
            <title><![CDATA[Introducing Angular Visual Storybook - Learn Angular Through Beautiful Infographics]]></title>
            <link>https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook</link>
            <guid>https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook</guid>
            <pubDate>Mon, 15 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview: I'm thrilled to introduce Angular Visual Storybook - an interactive learning resource that transforms complex Angular concepts into...]]></description>
            <content:encoded><![CDATA[<p><strong>Overview:</strong></p>
<p>I'm thrilled to introduce <a href="https://sajeetharan.github.io/angular-graphic/" target="_blank" rel="noopener noreferrer">Angular Visual Storybook</a> - an interactive learning resource that transforms complex Angular concepts into easy-to-understand visual infographics. Whether you're a beginner starting your Angular journey or an experienced developer looking for quick reference guides, this comprehensive collection has something for everyone.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-angular-visual-storybook">What is Angular Visual Storybook?<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#what-is-angular-visual-storybook" class="hash-link" aria-label="Direct link to What is Angular Visual Storybook?" title="Direct link to What is Angular Visual Storybook?">​</a></h2>
<p>Angular Visual Storybook is a static website that provides a comprehensive visual guide to Angular development through <strong>26 beautifully designed infographics</strong>. It's built with pure HTML5, CSS3, and JavaScript - no frameworks required! The project is perfect for visual learners and developers who prefer a structured, comprehensive approach to learning Angular.</p>
<p>🔗 <strong>Live Demo:</strong> <a href="https://sajeetharan.github.io/angular-graphic/" target="_blank" rel="noopener noreferrer">sajeetharan.github.io/angular-graphic</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-features">🌟 Features<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#-features" class="hash-link" aria-label="Direct link to 🌟 Features" title="Direct link to 🌟 Features">​</a></h2>
<ul>
<li><strong>📚 26 Comprehensive Topics</strong> - From Angular Overview to AI Integration</li>
<li><strong>🎨 Beautiful Design</strong> - Modern, responsive UI with smooth animations</li>
<li><strong>🔒 Image Protection</strong> - Multiple layers of protection to prevent unauthorized downloading</li>
<li><strong>📱 Mobile Friendly</strong> - Fully responsive design that works on all devices</li>
<li><strong>♿ Accessible</strong> - WCAG-compliant with keyboard navigation support</li>
<li><strong>🚀 Performance Optimized</strong> - Fast loading with intersection observers and lazy loading</li>
<li><strong>🔍 Search Functionality</strong> - Quick search through topics in the sidebar</li>
<li><strong>📊 Progress Tracking</strong> - Visual progress bar as you scroll through content</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="topics-covered">Topics Covered<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#topics-covered" class="hash-link" aria-label="Direct link to Topics Covered" title="Direct link to Topics Covered">​</a></h2>
<p>The storybook covers all major Angular topics from the official Angular documentation:</p>
<table><thead><tr><th>Core Concepts</th><th>Advanced Topics</th></tr></thead><tbody><tr><td>📖 Overview &amp; Essentials</td><td>⚡ Performance Optimization</td></tr><tr><td>💾 Installation &amp; Setup</td><td>🔒 Security</td></tr><tr><td>🧩 Components &amp; Templates</td><td>🖥️ Server-Side Rendering</td></tr><tr><td>🎯 Directives</td><td>⌨️ Angular CLI</td></tr><tr><td>💉 Dependency Injection</td><td>🛠️ Dev Tools</td></tr><tr><td>📡 Signals</td><td>💬 Language Service</td></tr><tr><td>🗺️ Routing</td><td>📐 Style Guide</td></tr><tr><td>📋 Forms</td><td>📦 Libraries</td></tr><tr><td>🌐 HTTP</td><td>🖱️ Drag &amp; Drop</td></tr><tr><td>🧪 Testing</td><td>🌍 Internationalization</td></tr><tr><td>🎬 Animations</td><td>🤖 AI Integration</td></tr><tr><td>♿ Accessibility</td><td>🔄 Keeping Up to Date</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="️-technologies-used">🛠️ Technologies Used<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#%EF%B8%8F-technologies-used" class="hash-link" aria-label="Direct link to 🛠️ Technologies Used" title="Direct link to 🛠️ Technologies Used">​</a></h2>
<p>What makes this project special is its simplicity:</p>
<ul>
<li><strong>Pure HTML5, CSS3, and JavaScript</strong> - No frameworks required!</li>
<li><strong>CSS Grid &amp; Flexbox</strong> for responsive layouts</li>
<li><strong>Intersection Observer API</strong> for scroll detection</li>
<li><strong>Modern ES6+ JavaScript</strong> features</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quick-start">Quick Start<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#quick-start" class="hash-link" aria-label="Direct link to Quick Start" title="Direct link to Quick Start">​</a></h2>
<p>Want to run it locally? It's incredibly simple:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Clone the repository</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">git clone https://github.com/sajeetharan/angular-graphic.git</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cd angular-graphic</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Using Python</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">python -m http.server 8000</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Or using Node.js</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx http-server</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Then visit http://localhost:8000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-image-protection-features">🔒 Image Protection Features<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#-image-protection-features" class="hash-link" aria-label="Direct link to 🔒 Image Protection Features" title="Direct link to 🔒 Image Protection Features">​</a></h2>
<p>The website implements multiple layers of image protection:</p>
<ol>
<li><strong>Right-Click Prevention</strong> - Context menu disabled on images</li>
<li><strong>Drag-and-Drop Blocking</strong> - Images cannot be dragged</li>
<li><strong>Keyboard Shortcut Blocking</strong> - Common save shortcuts are intercepted</li>
<li><strong>CSS Protection</strong> - User-select and drag properties disabled</li>
<li><strong>Visual Feedback</strong> - Warning overlay when protection is triggered</li>
<li><strong>Mobile Long-Press Protection</strong> - Touch events handled to prevent saving</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-i-built-this">Why I Built This<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#why-i-built-this" class="hash-link" aria-label="Direct link to Why I Built This" title="Direct link to Why I Built This">​</a></h2>
<p>Learning Angular can be overwhelming with its extensive documentation and numerous concepts. I wanted to create a resource that:</p>
<ul>
<li><strong>Simplifies complex concepts</strong> through visual representation</li>
<li><strong>Provides quick reference</strong> for experienced developers</li>
<li><strong>Offers an engaging learning experience</strong> for beginners</li>
<li><strong>Works offline</strong> once loaded - perfect for on-the-go learning</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-customization">🎨 Customization<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#-customization" class="hash-link" aria-label="Direct link to 🎨 Customization" title="Direct link to 🎨 Customization">​</a></h2>
<p>The project is highly customizable. You can easily modify colors by editing CSS variables:</p>
<div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token selector pseudo-class" style="color:rgb(255, 121, 198)">:root</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">--primary-color</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token hexcode color">#dd0031</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">/* Angular red */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">--secondary-color</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token hexcode color">#c3002f</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">/* Darker red */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">--accent-color</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token hexcode color">#0066ff</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">/* Blue accent */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="contributing">Contributing<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#contributing" class="hash-link" aria-label="Direct link to Contributing" title="Direct link to Contributing">​</a></h2>
<p>Contributions are welcome! If you have ideas for new infographics or improvements:</p>
<ol>
<li>Fork the repository</li>
<li>Create your feature branch (<code>git checkout -b feature/AmazingFeature</code>)</li>
<li>Commit your changes</li>
<li>Push to the branch</li>
<li>Open a Pull Request</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="-acknowledgments">🙏 Acknowledgments<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#-acknowledgments" class="hash-link" aria-label="Direct link to 🙏 Acknowledgments" title="Direct link to 🙏 Acknowledgments">​</a></h2>
<ul>
<li>Content structure inspired by <a href="https://angular.dev/" target="_blank" rel="noopener noreferrer">angular.dev</a></li>
<li>Infographics created for educational purposes</li>
<li>Built with ❤️ for the Angular community</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="get-started-today">Get Started Today<a href="https://www.sajeetharan.dev/blogs/2025/12/15/2025/12/introducing-angular-visual-storybook#get-started-today" class="hash-link" aria-label="Direct link to Get Started Today" title="Direct link to Get Started Today">​</a></h2>
<p>Ready to learn Angular visually?</p>
<ul>
<li>🌐 <strong>Visit the live site:</strong> <a href="https://sajeetharan.github.io/angular-graphic/" target="_blank" rel="noopener noreferrer">sajeetharan.github.io/angular-graphic</a></li>
<li>📦 <strong>Clone the repo:</strong> <a href="https://github.com/sajeetharan/angular-graphic" target="_blank" rel="noopener noreferrer">github.com/sajeetharan/angular-graphic</a></li>
</ul>
<hr>
<p><em>Have feedback or suggestions? Feel free to open an issue on GitHub or reach out to me on Twitter!</em></p>]]></content:encoded>
            <category>angular</category>
            <category>infographics</category>
            <category>learning</category>
            <category>visual-guide</category>
            <category>developer-tools</category>
            <category>education</category>
            <category>web-development</category>
        </item>
        <item>
            <title><![CDATA[Partial Document Update Samples with Cosmos DB REST Operation]]></title>
            <link>https://www.sajeetharan.dev/blogs/2022/02/22/2022/02/leveraging-partial-document-update-with-with-cosmos-db-rest-operation</link>
            <guid>https://www.sajeetharan.dev/blogs/2022/02/22/2022/02/leveraging-partial-document-update-with-with-cosmos-db-rest-operation</guid>
            <pubDate>Tue, 22 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview : In last November 2021, Cosmos DB team has announced support for patching documents with SQL API which was the top requested features in the user...]]></description>
            <content:encoded><![CDATA[<p><strong>Overview :</strong></p>
<p>In last November 2021, Cosmos DB team has announced support for <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/partial-document-update" target="_blank" rel="noopener noreferrer">patching documents</a> with SQL API which was the top requested features in the user voice. This is a useful and long-awaited feature among users. Prior to this announcement the only way to change the stored document was to completely <strong>replace</strong> it. Users will be able to perform Partial updates with all the Cosmos DB SDKs ( JAVA, . Net , JS ) and also <a href="https://docs.microsoft.com/en-us/rest/api/cosmos-db/patch-a-document" target="_blank" rel="noopener noreferrer">Cosmos DB REST API</a>.</p>
<p><strong>Use Case:</strong></p>
<p>Let's look at a scenario of a dashboard application where user need to display the System and it's features. User has decided to use Cosmos DB as a database to store the data of a <strong>System and it's features</strong>. A sample document would look as follows.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "ApplicationId": "App-01",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "ApplicationName": "New Cosmos Client",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "Description": "This shows the users and interactions",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "IsDraft": 0,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "IsSaved": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "Features": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            "SystemID": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            "Features": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureID": 4,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureName": "Patch",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "IsActive": false</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureID": 35,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureName": "Feature-a-2",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "IsActive": false</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureID": 36,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "FeatureName": "test-feature-a-3",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    "IsActive": true</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "id": "af3dfd7a-b7e9-4467-a2ca-9c6be7ad5b9f",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "_rid": "S1xQAKKOTBABAAAAAAAAAA==",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "_self": "dbs/S1xQAA==/colls/S1xQAKKOTBA=/docs/S1xQAKKOTBABAAAAAAAAAA==/",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "_etag": "\"31003582-0000-0700-0000-6213cb6b0000\"",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "_attachments": "attachments/",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "_ts": 1645464427</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's look at some of the scenarios where user needs to perform patch operations.</p>
<p><strong>Patch Scenario 1:</strong> &nbsp;Add a new record (JSON object) under <strong>Features</strong> parent array</p>
<p><strong>JSON object to Add:</strong></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "SystemID": 2,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "Features": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          "FeatureID": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          "FeatureName": "Reports",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          "IsActive": false</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can refer my previous blog on How to setup Rest Operations with <a href="https://sajeetharan.com/2019/07/01/easily-explore-cosmos-db-rest-apis-with-postman/" target="_blank" rel="noopener noreferrer">Postman</a>. Once you've configured the setup with the underlying database and container. Here we need to insert a new Object within the Features array, certainly we can leverage the <strong>Single Add</strong> Operation. And the sample request Body will be like,</p>
<p><strong>Patch Url :</strong> [https://account/dbs/dbName/colls/Patch/docs/id of the document](<a href="https://account/dbs/dbName/colls/Patch/docs/id" target="_blank" rel="noopener noreferrer">https://account/dbs/dbName/colls/Patch/docs/id</a> of the document) and the header "<strong>x-ms-documentdb-partitionkey</strong>" is set to the partition key value which is the "<strong>ApplicationId</strong>" <strong>"App-01"</strong>. And we need to specify the path as <strong>"/Features/-"</strong></p>
<figure><p><img decoding="async" loading="lazy" src="https://sajeetharan.wordpress.com/wp-content/uploads/2022/02/image-1.png?w=1024" alt="" class="img_ev3q"></p><figcaption><p>Add new JSON object under Features Array</p></figcaption></figure>
<p>On a successful response, in the backend you will see that a new Object that is shown above will be added to the Features array.</p>
<p><strong>Patch Scenario 2:</strong> &nbsp;Update the Application Description in the root Object to <strong>"Testing Patch with REST API"</strong></p>
<p><img decoding="async" loading="lazy" src="https://sajeetharan.wordpress.com/wp-content/uploads/2022/02/image-3.png?w=1024" alt="" class="img_ev3q"></p>
<p><strong>Patch Scenario 3:</strong> &nbsp;Update only a specific <strong>Feature object</strong> in array for a given <strong>Features</strong> parent object like <strong>FeatureName</strong> . Let's assume if we need to update the Object at the 0th index and then update the First <strong>Features</strong> Object,</p>
<p><img decoding="async" loading="lazy" src="https://sajeetharan.wordpress.com/wp-content/uploads/2022/02/image-4.png?w=1024" alt="" class="img_ev3q"></p>
<p><strong>Patch Scenario 4 :</strong> Perform all the above operations as a single request</p>
<p>Since Partial document update supports up to 10 operations in a single request, all the above operations can be merged. User needs to combine all the operations as one as below,</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   "operations":[</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "op":"replace",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "path":"/Features/0/Features/0/FeatureName",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "value":"Patch Testing"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "op":"set",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "path":"/Description",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         "value":"Testing Patch with REST API"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "op":"add",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "path":"/Features/-",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "value":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "SystemID": 2,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "Features": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">           {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">               "FeatureID": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">               "FeatureName": "Reports",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">               "IsActive": false</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">           }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Hope these samples help you to perform different operations at different path using Cosmos Rest API. Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>azure-cosmosdb</category>
            <category>cosmosdb</category>
            <category>partialupdate</category>
            <category>patch</category>
            <category>postman</category>
            <category>rest</category>
        </item>
        <item>
            <title><![CDATA[Cosmos DB Pagination &amp; Continuation Tokens with JavaScript]]></title>
            <link>https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript</link>
            <guid>https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript</guid>
            <pubDate>Tue, 08 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview: As a Developer, If you have a requirement to have list of work items which are approved to be displayed in a Grid View. You would tend to query...]]></description>
            <content:encoded><![CDATA[<h4 class="anchor anchorWithStickyNavbar_LWe7" id="overview"><strong>Overview:</strong><a href="https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript#overview" class="hash-link" aria-label="Direct link to overview" title="Direct link to overview">​</a></h4>
<p>As a Developer, If you have a requirement to have list of work items which are approved to be displayed in a Grid View. You would tend to query for all approved work items and display them in the grid, one point to note is that since the amount of approved work items might grow over time, hence loading the data would get slower and slower due to having to download more items. In general, this is where pagination comes into play in front end development, which means you don't need to necessarily download all records, just download a page of records at a time. If you are using Cosmos DB as a backend, this <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/sql/sql-query-pagination" target="_blank" rel="noopener noreferrer">feature</a> is supported out of the box via the use of <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/sql/sql-query-pagination#continuation-tokens" target="_blank" rel="noopener noreferrer">Continuation Token.</a> Cosmos DB SDKs utilize a continuation strategy when managing the results returned from the queries.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="pagination-with-azurecosmos-sdk"><strong>Pagination with @Azure/cosmos SDK:</strong><a href="https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript#pagination-with-azurecosmos-sdk" class="hash-link" aria-label="Direct link to pagination-with-azurecosmos-sdk" title="Direct link to pagination-with-azurecosmos-sdk">​</a></h4>
<p>One of the frequent questions I have come across on forums is on How to Implement Pagination with <a href="https://www.npmjs.com/package/@azure/cosmos" target="_blank" rel="noopener noreferrer">@azure/cosmos</a> SDK with JavaScript. With this post , I wanted to keep it simple and add a <a href="https://github.com/sajeetharan/cosmos-db-js-pagination-sample" target="_blank" rel="noopener noreferrer">very minimal quick start</a> on how to implementation pagination with .js SDK. You can follow the steps given in the <a href="https://github.com/sajeetharan/cosmos-db-js-pagination-sample" target="_blank" rel="noopener noreferrer">repository</a>.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">Prerequisites:<a href="https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites:" title="Direct link to Prerequisites:">​</a></h4>
<ul>
<li>Create a CosmosDB Account of type SQL API and database named 'javascript' and collection named 'products'</li>
<li>Insert the data 'ProductsData.json' to CosmosDB using the&nbsp;<a href="https://docs.microsoft.com/en-us/azure/cosmos-db/import-data" target="_blank" rel="noopener noreferrer">Data Migration Tool</a></li>
</ul>
<p><strong>execute.ts</strong> is the start point of the application which invokes the CallPagination method defined in the <strong>pagination.service.ts</strong>.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">import dotenv from "dotenv"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">import { Helper } from './helper';</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">import PaginationService from './pagination.service';</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotenv.config()</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">const cosmosDB = new Helper();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">const pageMod = new PaginationService(cosmosDB);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">const callPagination = async () =&gt; {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    const result = await pageMod.executeSample(2, "")</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    console.log({</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        data: result.result,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        dataLength: result.result.length,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        hasMoreResult: result.hasMoreResults,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        contToken: result.continuationToken</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    });</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">};</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">callPagination();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Implementation is really simple as we are passing a simple query that has more than 40 records and we set the <strong>pageLimit</strong> as 5 which is the max number of items to be returned in single call.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain"> public async executeSample(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    pageLimit: number = 5,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    contToken: string = ""</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  ): Promise&lt;{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    result: Array&lt;any&gt;;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    hasMoreResults: boolean;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    continuationToken: string;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }&gt; {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    const sqlQuery =</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      `SELECT * from products where products.CategoryName = "Bikes, Road Bikes"`</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    console.log({ sqlQuery })</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    const { result, hasMoreResults, continuationToken } =</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      await this.cosmosHelper.queryContainerNext(</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          query: sqlQuery</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          maxItemCount: pageLimit,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          continuationToken: contToken</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        process.env.CONTAINER_NAME</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      );</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      result: result || [],</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      hasMoreResults: hasMoreResults || false,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      continuationToken: continuationToken || "",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    };</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can access the whole sample from this <a href="https://github.com/sajeetharan/cosmos-db-js-pagination-sample" target="_blank" rel="noopener noreferrer">link</a>.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="steps-to-run-the-application">Steps to Run the application<a href="https://www.sajeetharan.dev/blogs/2022/02/08/2022/02/cosmos-db-pagination-continuation-tokens-with-javascript#steps-to-run-the-application" class="hash-link" aria-label="Direct link to Steps to Run the application" title="Direct link to Steps to Run the application">​</a></h4>
<ul>
<li>Clone the Repository</li>
<li>Run&nbsp;<code>npm install</code></li>
<li>Replace the environment COSMOS_ENDPOINT,COSMOS_KEY,COSMOS_DATABASE_NAME,CONTAINER_NAME in the .env file</li>
<li>Run&nbsp;<code>npm start</code>&nbsp;run the application</li>
</ul>
<p>Hope this helps someone who wants to implement Pagination with JavaScript. Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>cosmosdb</category>
            <category>developers</category>
            <category>microsoft</category>
        </item>
        <item>
            <title><![CDATA[BOOK GIVEAWAY: Win a free copy of  "Cloud Scale Analytics with Azure Data Services "]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/10/25/2021/10/book-giveaway-win-a-free-copy-of-cloud-scale-analytics-with-azure-data-services</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/10/25/2021/10/book-giveaway-win-a-free-copy-of-cloud-scale-analytics-with-azure-data-services</guid>
            <pubDate>Mon, 25 Oct 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Hello folks! Azure Data Lake is a big data solution which allows organizations to ingest multiple data sets covering structured, unstructured, and...]]></description>
            <content:encoded><![CDATA[<p>Hello folks!</p>
<p><a href="https://azure.microsoft.com/en-in/solutions/data-lake/" target="_blank" rel="noopener noreferrer">Azure Data Lake</a> is a big data solution which allows organizations to ingest multiple data sets covering structured, unstructured, and semi-structured data into an infinitely scalable data lake enabling storage, processing, and analytics. It enables users to build their own customized analytical platform to fit any analytical requirements in terms of volume, speed, and quality.</p>
<figure><p><a href="https://www.amazon.com/Cloud-Scale-Analytics-Azure-Services/dp/1800562934/?maas=maas_adg_67481E3150DB21080DF715A863452FA7_afap_abs&amp;ref_=aa_maas" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" src="https://sajeetharan.wordpress.com/wp-content/uploads/2021/10/cloud-scale-analytics-with-azure-data-services.png?w=619" alt="" class="img_ev3q"></a></p><figcaption><p>Cloud Scale Analytics with Azure Data Services: Build modern data warehouses on Microsoft Azure</p></figcaption></figure>
<p>In the context of above, the book "<a href="https://www.amazon.com/Cloud-Scale-Analytics-Azure-Services/dp/1800562934/?maas=maas_adg_67481E3150DB21080DF715A863452FA7_afap_abs&amp;ref_=aa_maas" target="_blank" rel="noopener noreferrer">Cloud Scale Analytics with Azure Data Services</a>" book is your guide to learning all the features and capabilities of Azure data services for storing, processing, and analyzing data (structured, unstructured, and semi-structured) of any size. You will explore key techniques for ingesting and storing data and perform batch, streaming, and interactive analytics</p>
<p>The book also shows you how to overcome various challenges and complexities relating to productivity and scaling. Next, you will be able to develop and run massive data workloads to perform different actions. Using a cloud based big data-modern data warehouse–analytics setup, you will also be able to build secure, scalable data estates for enterprises. Finally, you will not only learn how to develop a data warehouse but also understand how to create enterprise-grade security and auditing big data programs.</p>
<p>By the end of this Azure book, you will have learned how to develop a powerful and efficient analytical platform to meet enterprise needs.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="win-your-free-copy">WIN YOUR FREE <a href="https://www.amazon.com/Cloud-Scale-Analytics-Azure-Services/dp/1800562934/?maas=maas_adg_67481E3150DB21080DF715A863452FA7_afap_abs&amp;ref_=aa_maas" target="_blank" rel="noopener noreferrer">COPY</a><a href="https://www.sajeetharan.dev/blogs/2021/10/25/2021/10/book-giveaway-win-a-free-copy-of-cloud-scale-analytics-with-azure-data-services#win-your-free-copy" class="hash-link" aria-label="Direct link to win-your-free-copy" title="Direct link to win-your-free-copy">​</a></h2>
<p>Enter your details and Click Submit to enter our monthly prize draw. Take your chance to receive one of the 10 free copies as give away.</p>]]></content:encoded>
            <category>adls</category>
            <category>analytics</category>
            <category>azure</category>
            <category>bigdata</category>
            <category>cosmosdb</category>
            <category>datalake</category>
            <category>ebook</category>
            <category>free</category>
            <category>giveaway</category>
            <category>hadoop</category>
            <category>packt</category>
            <category>spark</category>
        </item>
        <item>
            <title><![CDATA[Get to know how to query Azure Cosmos DB by using the SQL API]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api</guid>
            <pubDate>Thu, 27 May 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview : In this blog post you will learn about the Azure Cosmos DB SQL API queries and How to get started with Cosmos DB SQL API. I recently published a...]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="overview-">Overview :<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#overview-" class="hash-link" aria-label="Direct link to Overview :" title="Direct link to Overview :">​</a></h2>
<p>In this blog post you will learn about the Azure Cosmos DB SQL API queries and How to get started with Cosmos DB SQL API. I recently published a <a href="https://www.youtube.com/watch?v=20281Cl-GvM" target="_blank" rel="noopener noreferrer">video on youtube</a> and decided to have it available in blog as well. <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/introduction" target="_blank" rel="noopener noreferrer">Azure Cosmos DB</a> is a fully managed NoSQL multi model database service provided by Azure which is highly available, globally distributed, and responds back within the minimum latency in single digit millisecond. It's becoming the preferred database for developers on Azure to build modern day applications.</p>
<p>You can access the <a href="https://slides.com/sajeetharan/cosmos-sql" target="_blank" rel="noopener noreferrer">slides here</a> and repository for the queries <a href="https://github.com/sajeetharan/Cosmosdb-sql-api" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p>Azure supports multiple data models including documents, key-value, graph, and column-family with multi models APIs such as SQL,Mongo,Cassandra,Gremlin and Table. SQL APi is one of them and its oldest offerings on cosmos db. SQL API is also known as Core API which means that any new feature which is rolled out to cosmos db usually first available in SQL API accounts. It supports for querying the items using the Structured query language Syntax which provides a way to query JSON objects.</p>
<p>Also cosmos db SQL API queries can be done using any SDK we provide with Net, Java, Node and python.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/pasted-from-clipboard-ab1249081304655b7bb8ed8ec7c97ef0.png" width="706" height="484" class="img_ev3q"></p><figcaption><p>Azure Cosmos DB SQL API</p></figcaption></figure>
<p>Azure Cosmos DB is truly schema-free. Whenever you store data, it provides automatic indexing of JSON documents without requiring explicit schema or creation of secondary indexes.</p>
<p>The Azure Cosmos DB database account is a unique name space that gives you access to Azure Cosmos DB.</p>
<p>A database account consists of a set of databases, each containing multiple collections, each of which can contain stored procedures, triggers, UDFs, documents, and related attachments.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/pasted-from-clipboard-ab1249081304655b7bb8ed8ec7c97ef0.png" width="706" height="484" class="img_ev3q"></p><figcaption><p>Cosmos DB SQL API Account Structure</p></figcaption></figure>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ways-to-manage-cosmosdb-documents-">Ways to Manage Cosmosdb Documents :<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#ways-to-manage-cosmosdb-documents-" class="hash-link" aria-label="Direct link to Ways to Manage Cosmosdb Documents :" title="Direct link to Ways to Manage Cosmosdb Documents :">​</a></h2>
<p>With the Cosmos DB SQL API , you can create documents using a variety of different tools :</p>
<p><strong>Portal</strong>: The Data Explorer is a tool embedded within the Azure Cosmos DB blade in the Azure Portal that allows you to view, modify and add documents to your Cosmos DB API collections. Within the explorer, you can upload one or more JSON documents directly into a specific database or collection which i will be showing in a bit</p>
<p><strong>SDK</strong>: Cosmos DB database service that was released prior to Azure Cosmos DB featured a variety of SDKs available across many languages</p>
<p><strong>REST API</strong> : As we mentioned previously, JSON documents stored in SQL API are managed through a well-defined hierarchy of database resources. These resources are each addressable using a unique URI. Since each resource has a unique URI, many of the concepts in Restful API design applies to SQL API resources</p>
<p><strong>Data Migration Tool:</strong> The open-source Cosmos DB data <a href="https://github.com/azure/azure-documentdb-datamigrationtool" target="_blank" rel="noopener noreferrer">migration tool</a> which allows you to import data into a SQL API collection from various sources including MongoDB, SQL Server, Table Storage, Amazon DynamoDB, HBase and other Cosmosdb collections.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">Prerequisites:<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites:" title="Direct link to Prerequisites:">​</a></h2>
<p>For this overview demo , I will be using a dataset Tweets which contains Tweets by users across the world on certain tags says <strong>#Azure</strong> and <strong>#Cosmosdb</strong></p>
<p>To replicate the demo you can use the Emulator which you can download from here <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator" target="_blank" rel="noopener noreferrer">Cosmosdb Emulator</a> . Or you can create a <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/free-tier" target="_blank" rel="noopener noreferrer">Cosmosdb free tier</a> account which is handy for developers.Azure Cosmos DB free tier makes it easy to get started, develop, test your applications, or even run small production workloads for free. When free tier is enabled on an account, you'll get the first 1000 RU/s and 25 GB of storage in the account for free.</p>
<p>In this demo let me migrate this sample dataset tweets which has 1000 recent tweets from users who actually tweeted about different technologies. I have uploaded the <a href="https://github.com/sajeetharan/Cosmosdb-sql-api" target="_blank" rel="noopener noreferrer">dataset</a> in my github account and we will be using the same to understand different queries.</p>
<ul>
<li>Create a CosmosDB Account of type SQL API and database/collection named Tweets</li>
<li>Insert the data inside the folder Tweets to CosmosDB using the&nbsp;<a href="https://docs.microsoft.com/en-us/azure/cosmos-db/import-data" target="_blank" rel="noopener noreferrer">Data Migration Tool</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="sql-api-queries-">SQL API Queries :<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#sql-api-queries-" class="hash-link" aria-label="Direct link to SQL API Queries :" title="Direct link to SQL API Queries :">​</a></h2>
<p>Once you created the Cosmos DB account on Azure , Navigate to <strong>Settings -&gt; Key</strong> and copy the Endpoint and the Url for the Cosmos DB account and replace the values in the <a href="https://github.com/sajeetharan/Cosmosdb-sql-api/blob/master/Program.cs" target="_blank" rel="noopener noreferrer">Program.cs</a> ( This is not recommended for production use , use Keyvault instead).</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/07777-screenshot-2021-10-05-091025-3f478bcded0a22612d32cbcf5597cd7b.png" width="931" height="367" class="img_ev3q"></p><figcaption><p>Obtain Keys and Endpoint from Azure portal</p></figcaption></figure>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">  // The Azure Cosmos DB endpoint for running this sample.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private static readonly string EndpointUri = "https://sajee-cosmos-notebooks.documents.azure.com:443/";</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  // The primary key for the Azure Cosmos account.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  private static readonly string PrimaryKey = "==";</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Before dive into the queries , let me explain one of the most important thing to deal with queries in Cosmos DB. In Cosmos DB SQL API accounts, there are two ways to read data.</p>
<p>P<strong>oint reads –</strong> Which denotes you can do a key value lookup on a single item id and a partition key. Point reads usually cost 1 RU With a latency under 10 Milli seconds.</p>
<p><strong>SQL queries</strong> - SQL queries consume more Rus in general than the point reads . So if you need a single item, point reads are cheaper and faster.</p>
<p>As a developer we tend to execute select * from table which might cause you more RUs since you are reading the whole data across multiple partitions.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/pasted-from-clipboard-ab1249081304655b7bb8ed8ec7c97ef0.png" width="706" height="484" class="img_ev3q"></p><figcaption><p>Query vs Point Read</p></figcaption></figure>
<p>Let's dive into some of the queries with SQL API</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-1--select-all"><strong>Query 1 : Select All</strong><a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-1--select-all" class="hash-link" aria-label="Direct link to query-1--select-all" title="Direct link to query-1--select-all">​</a></h4>
<p>To retrieve all items from the container, in this case let's get all the tweets. Type this query into the query editor:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT *</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>...and click on&nbsp;<strong>Execute Query!</strong></p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/94a10-screenshot-2021-10-05-094722-fd8d21b991d78f0ab1119db621eb23ab.png" width="651" height="493" class="img_ev3q"></p><figcaption><p>Cosmos DB SQL API queries</p></figcaption></figure>
<p>Few things to note here are, It retrieves the first 100 items from the container and if you need to retrieve the next 100, you could click on load more , under the hood it uses the pagination mechanism. Another handy thing here is that you can navigate to query stats and see more details on the query such as RUs, Document size, Execution time etc.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/608e8-image-8efcdd216647e59bec04bbda8a2e252f.png" width="528" height="315" class="img_ev3q"></p><figcaption><p>Query Metrics</p></figcaption></figure>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-2--filter-path"><strong>Query 2 : Filter Path</strong><a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-2--filter-path" class="hash-link" aria-label="Direct link to query-2--filter-path" title="Direct link to query-2--filter-path">​</a></h4>
<p>When referring to fields you must use the alias you define in the&nbsp;<code>FROM</code>&nbsp;clause. We have to provide the full "path" to the properties of the objects within the container. For example, if you need to get the RetweetCount from the container for all the items.</p>
<p>SELECT tweets.RetweetCount<br>
<!-- -->FROM tweets</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-3--join"><strong>Query 3 : Join</strong><a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-3--join" class="hash-link" aria-label="Direct link to query-3--join" title="Direct link to query-3--join">​</a></h4>
<p>Lets see how we can find out the hashtags that have been used in all the tweets. We can use the&nbsp;<code>JOIN</code>&nbsp;keyword to join to our hashtags array in each tweet. We can also give it an alias and inspect its properties.</p>
<p>Let's see the&nbsp;<code>JOIN</code>&nbsp;in action. Try this query:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT hashtags</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN hashtags IN tweets.Hashtags</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now that we know how to join to our child array we can use it for filtering. Lets find all other hashtags that have been used along with the known hashtags (#Azure, #CosmosDB):</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT hashtags</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN hashutcDate IN tweets.Hashtags</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">WHERE hashtags.text NOT IN ("CosmosDB", "Azure")</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Similarly we can use OR,IN,DISTINCT,GROUPBY etc.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-4--keywords-inor-etc"><strong>Query 4 : KEYWORDS (IN,OR etc)</strong><a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-4--keywords-inor-etc" class="hash-link" aria-label="Direct link to query-4--keywords-inor-etc" title="Direct link to query-4--keywords-inor-etc">​</a></h4>
<p>To return the entire tweet where the indices of the hashtag is between 11 and 18 simply by selecting the tweets rather than the indices</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN hashtags IN tweets.Hashtags</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN indices IN hashtags.indices</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">WHERE indices BETWEEN 11 AND 18</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-5--orderby-and-top">Query 5 : ORDERBY and TOP<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-5--orderby-and-top" class="hash-link" aria-label="Direct link to Query 5 : ORDERBY and TOP" title="Direct link to Query 5 : ORDERBY and TOP">​</a></h4>
<p>We can also order our query so we can find the most recent tweet(s) and retrieve the top 5 tweets. (use ASC for ascending and DESC for Descending) :</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT TOP 5 tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN hashtags IN tweets.Hashtags</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JOIN indices IN hashtags.indices</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">WHERE indices BETWEEN 21 AND 28</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ORDER BY tweets</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-6--projection">Query 6 : PROJECTION<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-6--projection" class="hash-link" aria-label="Direct link to Query 6 : PROJECTION" title="Direct link to Query 6 : PROJECTION">​</a></h4>
<p>We can use a feature called&nbsp;<strong>Projection</strong>&nbsp;to create an entirely new result set. We could use this to create a common structure or to make it match a structure we already have.</p>
<p>Try this query:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT tweets.CreatedBy.Name AS Name,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">		tweets.FullText AS Text,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">		tweets.CreatedAt AS CreatedTime,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        tweets.TweetDTO.metadata.iso_language_code AS LanguageCode</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="query-7--user-defined-function">Query 7 : USER DEFINED FUNCTION<a href="https://www.sajeetharan.dev/blogs/2021/05/27/2021/05/getting-started-with-cosmos-db-sql-api#query-7--user-defined-function" class="hash-link" aria-label="Direct link to Query 7 : USER DEFINED FUNCTION" title="Direct link to Query 7 : USER DEFINED FUNCTION">​</a></h4>
<p>The SQL API supports javascript User defined functions, there that you can use on this server called <strong>displayDate</strong> which removes the time parts of a UTC date string.</p>
<p>This is the function :</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">function displayDate(inputDate) {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return inputDate.split('T')[0];</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's have a go at using it</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SELECT tweets.CreatedAt,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    udf.displayDate(tweets.CreatedAt) AS FormattedDate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">FROM tweets</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The SQL API also supports stored procedures written in JavaScript which enables you to perform ACID transactions over multiple records. This allows scalable and almost unlimited expandability on the functionality Azure Cosmos DB can offer.</p>
<p>These are some of the basic queries to get started with CosmosDB SQL API. If you want to get to know more about SQL API the following references would be useful.</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/sql/create-sql-api-dotnet" target="_blank" rel="noopener noreferrer">SQL API quickstart</a></li>
<li>D<a href="https://docs.microsoft.com/en-us/azure/cosmos-db/import-data" target="_blank" rel="noopener noreferrer">ata Migration Tools Cosmos DB</a></li>
</ul>
<p>Hope this post help you get started with CosmosDB SQL API! Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>c</category>
            <category>cosmosdb</category>
            <category>datamigration</category>
            <category>developers</category>
            <category>migration</category>
            <category>nosql</category>
            <category>projection</category>
            <category>sql</category>
            <category>sqlapi</category>
        </item>
        <item>
            <title><![CDATA[Publish an Angular Application to Azure static web apps with Azure Devops]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops</guid>
            <pubDate>Thu, 01 Apr 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Microsoft introduced App Service Static Web Apps in Preview at Build 2020 as"Azure static web apps", a service which allows web developers to build and...]]></description>
            <content:encoded><![CDATA[<p>Microsoft introduced App Service Static Web Apps in Preview at Build 2020 as"<a href="https://azure.microsoft.com/en-us/services/app-service/static/" target="_blank" rel="noopener noreferrer">Azure static web apps</a>", a service which allows web developers to build and deploy website to any environment from Github repository for free. Developers can deploy applications in minute while taking the advantage of scaling and cost savings offered by azure functions as backend. One of the frequent questions that i heard from the developers was the availability of Azure Devops support with Azure static web apps.</p>
<p>I have already published an article which demonstrates how to deploy to Azure Static Web Apps using <a href="https://sajeetharan.wordpress.com/2020/05/20/azure-static-web-apps/" target="_blank" rel="noopener noreferrer">GithubActions</a>. Azure static web apps team announced the public preview of <a href="https://azure.microsoft.com/en-us/updates/public-preview-azure-static-web-apps-now-supports-deployment-with-azure-devops/" target="_blank" rel="noopener noreferrer">Azure Devops with Azure static web apps</a> yesterday.</p>
<p>In this post you I will walk you through on how to deploy an angular application to Azure static web apps using Azure <a href="https://dev.azure.com/" target="_blank" rel="noopener noreferrer">Devops</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">PreRequisites:<a href="https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops#prerequisites" class="hash-link" aria-label="Direct link to PreRequisites:" title="Direct link to PreRequisites:">​</a></h2>
<ul>
<li>An&nbsp;<a href="https://azure.microsoft.com/en-us/" target="_blank" rel="noopener noreferrer">Azure</a>&nbsp;account (you can use free trial, If you don't have one, you can&nbsp;<a href="https://azure.microsoft.com/free/" target="_blank" rel="noopener noreferrer">create an account for free</a>)</li>
<li>Azure DevOps &nbsp;(If you need help getting started, see&nbsp;<a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?view=azure-devops&amp;preserve-view=true" target="_blank" rel="noopener noreferrer">Create</a> one)</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="step-1--create-a-devops-repository">Step 1 : Create a Devops repository<a href="https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops#step-1--create-a-devops-repository" class="hash-link" aria-label="Direct link to Step 1 : Create a Devops repository" title="Direct link to Step 1 : Create a Devops repository">​</a></h2>
<p>Navigate to <a href="https://dev.azure.com/" target="_blank" rel="noopener noreferrer">Dev.Azure.com</a> and create a new Devops Repository as below</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/9d434-2021-04-01_9-39-51-791x1024-1-a7256a09de77cbf853e784601b5f4ee9.png" width="791" height="1024" class="img_ev3q"></p><figcaption><p>Azure Devops repository</p></figcaption></figure>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="step-2--import-your-static-web-application-to-azure-devops-repository">Step 2 : Import your static web application to Azure Devops repository<a href="https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops#step-2--import-your-static-web-application-to-azure-devops-repository" class="hash-link" aria-label="Direct link to Step 2 : Import your static web application to Azure Devops repository" title="Direct link to Step 2 : Import your static web application to Azure Devops repository">​</a></h2>
<p><a href="https://github.com/microsoft/static-web-apps-gallery-code-samples" target="_blank" rel="noopener noreferrer">https://github.com/microsoft/static-web-apps-gallery-code-samples</a>Next step is to import the web application from any source control to your newly created Azure Devops repository. In this case i am importing the same "<a href="https://github.com/sajeetharan/meme4fun" target="_blank" rel="noopener noreferrer">Meme generator</a>" app which was made of Angular. Meme4Fun is an app to create custom programming memes from a picture and it also identifies features of people in the image which is available as part of code samples for Azure static web apps.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/5e88c-2021-04-01_12-38-19-609x1024-1-1547d356d89fbf2a0adb1c60024a7ded.png" width="609" height="1024" class="img_ev3q"></p><figcaption><p>Import Repository to Azure Devops</p></figcaption></figure>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="step-3--create-a-static-web-app-on-azure">Step 3 : Create a static web app on Azure<a href="https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops#step-3--create-a-static-web-app-on-azure" class="hash-link" aria-label="Direct link to Step 3 : Create a static web app on Azure" title="Direct link to Step 3 : Create a static web app on Azure">​</a></h2>
<p>Next step is to create the static web application on azure, navigate to azure portal and create a new resource by searching for Static Web apps, and create it.</p>
<p><strong>Note</strong> : <strong>Since I am going to leverage Azure Devops as the deployment method, select Other as the option.</strong></p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/78d12-2021-04-01_13-03-57-934x1024-1-a49b1baf94e652ebcb9de1056ec00aae.png" width="934" height="1024" class="img_ev3q"></p><figcaption><p>Choose Devops as the Deployment</p></figcaption></figure>
<p>Once the deployment is successful, navigate to the new Static Web Apps resource and select Manage deployment token.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/24c50-2021-04-01_13-09-49-1024x127-1-11e96a44216723adbf252804797d894d.png" width="1024" height="127" class="img_ev3q"></p><figcaption><p>Manage deployment token</p></figcaption></figure>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="step-4-create-the-pipeline-task-in-azure-devops">Step 4: Create the Pipeline task in Azure Devops<a href="https://www.sajeetharan.dev/blogs/2021/04/01/2021/04/azure-static-web-apps-with-azure-devops#step-4-create-the-pipeline-task-in-azure-devops" class="hash-link" aria-label="Direct link to Step 4: Create the Pipeline task in Azure Devops" title="Direct link to Step 4: Create the Pipeline task in Azure Devops">​</a></h2>
<p>If you are using Azure Devops to deploy applications in the past, you will need to have the pipeline in plact to deploy to particular resource. In this case, lets create a build pipeline to deploy the angular application.</p>
<p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="1024" height="117" class="img_ev3q"></p>
<p>Next step is to select the template, since we are deploying an angular application, you can select the template as angular with nodejs</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/d5ba6-2021-04-01_13-15-12-900x1024-1-d43b82f8b323c43812d990991cd06d09.png" width="900" height="1024" class="img_ev3q"></p><figcaption><p>Angular template</p></figcaption></figure>
<p>Also for static web apps it is important to include the following step in the yaml which has the <strong>a<code>pp_location</code>,&nbsp;<code>api_location</code>, and&nbsp;<code>output_location</code></strong> , you need to pass those values if you have those details if not keep it empty.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/5b978-image-14d03f625d5d5469fbd1e438dc6b138f.png" width="953" height="414" class="img_ev3q"></p><figcaption><p><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-devops" target="_blank" rel="noopener noreferrer">Different values details</a></p></figcaption></figure>
<p>and the final configure YAML will look similar to the below,</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Node.js with Angular</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Build a Node.js project that uses Angular.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Add steps that analyze code, save build artifacts, deploy, and more:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># https://docs.microsoft.com/azure/devops/pipelines/languages/javascript</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">trigger:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- master</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">pool:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  vmImage: ubuntu-latest</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">steps:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- task: NodeTool@0</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  inputs:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    versionSpec: '10.x'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  displayName: 'Install Node.js'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- script: |</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    npm install -g @angular/cli</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    npm install</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ng build --prod</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  displayName: 'npm install and build'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- task: AzureStaticWebApp@0</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  inputs:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      app_location: "/" </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      api_location: "api"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      output_location: "dist/meme4fun"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  env:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      azure_static_web_apps_api_token: $(deployment_token)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Next step is to provide the The&nbsp;<code>**azure_static_web_apps_api_token**</code>&nbsp;value is self managed and is manually configured. Select Variables in the pipeline and create a new variable named as "deployment_token"(matching the name in the workflow) below.</p>
<figure><p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="1021" height="60" class="img_ev3q"></p><figcaption><p>Add new Variable</p></figcaption></figure>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/23ed4-2021-04-01_13-22-24-588x1024-1-780532b48ccef14eefe0fa515b2e3cf4.png" width="588" height="1023" class="img_ev3q"></p><figcaption><p>Paste the deployment_token value which was copied from Azure portal</p></figcaption></figure>
<p>Make sure to check "Keep the value secret" and save the workflow and run.</p>
<p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="1024" height="55" class="img_ev3q"></p>
<p>With that step Azure Devops will execute the pipeline and deploy the application to azure static web apps.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/0e809-2021-04-02_1-07-47-8822435b8d355e1318bf627ef0d12333.png" width="670" height="577" class="img_ev3q"></p><figcaption><p>Successful deployment</p></figcaption></figure>
<p>Now you can access the application from the static static web app from the URL.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/2d1e0-2021-04-02_1-09-47-1024x187-1-0018e42b8310a3f552414a9b53e193e8.png" width="1024" height="187" class="img_ev3q"></p><figcaption><p>Static web app with azure devops deployment</p></figcaption></figure>
<p>If you had any trouble in executing the above steps, you can watch the same tutorial published as a video <a href="https://www.youtube.com/watch?v=8m82Lh3yai8" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p>It's great to see that with few steps of configuration, i was able to deploy the application with Azure Devops. If you have enabled backend support with the azure functions, it can be deployed as well. Support with Azure Devops has been one of the most requested features by developers and great to see it in live now. It's your chance to explore various application deployments with different frameworks, hope this is useful. Cheers!</p>]]></content:encoded>
            <category>angular</category>
            <category>azure</category>
            <category>azurefunctions</category>
            <category>devops</category>
            <category>singlepage</category>
            <category>static</category>
            <category>staticwebapps</category>
        </item>
        <item>
            <title><![CDATA[How i built Serverless App 'MentorMe' with Azure Functions and Cosmosdb]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app</guid>
            <pubDate>Fri, 26 Feb 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview As per a survey, 57% of young individuals agreed they do not have the right connections to find a mentor and more than 50% of them couldn't find a...]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorWithStickyNavbar_LWe7" id="overview">Overview<a href="https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview">​</a></h3>
<p>As per a survey, 57% of young individuals agreed they do not have the right connections to find a mentor and more than 50% of them couldn't find a job that they are passionate about. As a result I was exploring if there is any platform that would solve this major problem. Yes, there are some existing online apps but those don't serve the complete purpose to the extent that i expected. I decided to start a pet project to build this platform during my spare time , in this post i will be sharing the architecture of the application and how i was able to quickly spin up this application.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites-to-build-and-deploy">&nbsp;<strong>Prerequisites to build and deploy</strong><a href="https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app#prerequisites-to-build-and-deploy" class="hash-link" aria-label="Direct link to prerequisites-to-build-and-deploy" title="Direct link to prerequisites-to-build-and-deploy">​</a></h3>
<p>As an Azure fan, i have used Azure as the cloud platform to deploy this solution. Here are some prerequisites first:</p>
<ul>
<li>An&nbsp;<a href="https://azure.microsoft.com/en-us/" target="_blank" rel="noopener noreferrer">Azure</a>&nbsp;account (don’t worry, deploying this app costed me almost&nbsp;<strong>nothing</strong>, you can use free trial)</li>
<li><a href="https://nodejs.org/en/" target="_blank" rel="noopener noreferrer">node</a>&nbsp;and&nbsp;<a href="https://www.npmjs.com/" target="_blank" rel="noopener noreferrer">npm</a>&nbsp;(preferably the latest versions)</li>
<li>VSCode and Android Studio</li>
</ul>
<p>As i explained in the previous posts, <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/introduction" target="_blank" rel="noopener noreferrer">Cosmosdb</a> and <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-serverless-api" target="_blank" rel="noopener noreferrer">Azure Functions</a> are great combo to build applications and deploy in quick time without worrying about underlying infrastructure. You can read about some of the reference architectures i have posted in the past from the below links,</p>
<ul>
<li><a href="https://sajeetharan.wordpress.com/2020/02/28/covid-escape-game-with-cosmosdb-and-python/" target="_blank" rel="noopener noreferrer">Game with Cosmosdb</a></li>
<li><a href="https://sajeetharan.wordpress.com/2019/06/13/how-azure-cosmosdb-functions-powerbi-iot-hub-could-solve-the-burning-traffic-problem/" target="_blank" rel="noopener noreferrer">How Azure CosmosDB + Functions + IOT hub + PowerBI could solve the burning Traffic problem</a></li>
<li><a href="https://sajeetharan.wordpress.com/2020/02/20/how-to-build-facial-recognition-solution/" target="_blank" rel="noopener noreferrer">Facial Recognition solution for the fraud prevention using Azure AI and Cosmosdb</a></li>
<li><a href="https://sajeetharan.wordpress.com/2020/02/02/create-github-issue-report-with-azure/" target="_blank" rel="noopener noreferrer">Github Issue Reporter with Azure Function and CosmosDB</a></li>
</ul>
<p>Let me dive into each component in the architecture of 'MentorLab'.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="how-it-works"><strong>How it works?</strong><a href="https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app#how-it-works" class="hash-link" aria-label="Direct link to how-it-works" title="Direct link to how-it-works">​</a></h3>
<p>MentorLab has been made to scale up the existing students and mentors using Azure Services and Serverless Architecture to provide a cost-economic one stop solution which is dependable and truly secure. The objective is to give the students a platform&nbsp;which is built on a&nbsp;<strong>serverless architecture</strong>&nbsp;and can be remotely accessed irrespective of geographic location.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="there-are-two-facets-of-this-solution">There are two facets of this solution<a href="https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app#there-are-two-facets-of-this-solution" class="hash-link" aria-label="Direct link to There are two facets of this solution" title="Direct link to There are two facets of this solution">​</a></h3>
<ul>
<li>Mentor Side - Dashboard (Flutter)</li>
<li>Students Side - Mobile App (Flutter)</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="azure-services-used"><a href="https://github.com/Chikitsak-Care/Chikitsak#azure-services-used-" target="_blank" rel="noopener noreferrer"></a>Azure Services Used&nbsp;<a href="https://www.sajeetharan.dev/blogs/2021/02/26/2021/02/how-i-built-serverless-app#azure-services-used" class="hash-link" aria-label="Direct link to azure-services-used" title="Direct link to azure-services-used">​</a></h4>
<ul>
<li>Github Actions</li>
<li>Active Directory (A2D)</li>
<li>Blob Storage</li>
<li>Azure Cosmos DB</li>
<li>API Management</li>
<li>Azure Functions</li>
<li>Monitor</li>
</ul>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/1eb6d-mentor-2-f972b24b02a81d74fcc43fcc85dfed18.png" width="719" height="563" class="img_ev3q"></p><figcaption><p>Architecture of MentorMe App</p></figcaption></figure>
<p>Flutter App is the front end application which is accessed by Mentor and Developer with different types of logins, All the requests from the mobile app will be router via the <a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview" target="_blank" rel="noopener noreferrer">AppGateway</a>. The backend APIs are built as servelress APIs with Azure functions with the support of <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-cosmos-db-triggered-function" target="_blank" rel="noopener noreferrer">Cosmosdb</a> Trigger. <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/serverless" target="_blank" rel="noopener noreferrer">Cosmosd's serverless</a> feature is a great offering when building these kind of applications, as it is a cost-effective option for databases with sporadic traffic patterns and modest bursts. It eliminates the concept of provisioned throughput and instead&nbsp;charges you for the RUs your database operations consume. In this scenario, i have chosen Mongo API for the CRUD operations. The APIs are registered as endpoints with the Azure API management with right policies in place.</p>
<p>Some of the additional components you could see in the diagram are the CI/CD pipelines with Github Actions and Azure AD B2C for the authorization, Key vault for storing the connection strings,keys in a secured way. And finally application insights to generate the related metrics and for troubleshooting.</p>
<p>It nearly took just 3 days to build this application and going forward i am planning to add more features such as video conferencing with the help of <a href="https://azure.microsoft.com/en-us/services/communication-services/" target="_blank" rel="noopener noreferrer">Azure Communication</a> and <a href="https://azure.microsoft.com/en-us/services/media-services/" target="_blank" rel="noopener noreferrer">Media services</a> . All these components just costs 36$/Month to host this application on Azure.</p>
<p>Hope this reference architecture helps you to kickstart your work for similar application. Feel free to add your thoughts/Questions as comments in the section below. Happy Hacking!</p>]]></content:encoded>
            <category>apimanagement</category>
            <category>architecture</category>
            <category>azure</category>
            <category>azurefunctions</category>
            <category>cloud</category>
            <category>cosmosdb</category>
            <category>flutter</category>
            <category>microservices</category>
            <category>mobile</category>
            <category>notification</category>
            <category>reference</category>
            <category>serverless</category>
        </item>
        <item>
            <title><![CDATA[Effective Monitoring : How to Setup SMS alerts for any unhealthy resource on Azure]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/01/20/2021/01/setup-sms-alerts-for-any-resource-on-azure</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/01/20/2021/01/setup-sms-alerts-for-any-resource-on-azure</guid>
            <pubDate>Wed, 20 Jan 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[If you are hosting your application on any environment whether it's in cloud or on-prem, an effective monitoring helps to increase the uptime by proactively...]]></description>
            <content:encoded><![CDATA[<p>If you are hosting your application on any environment whether it's in cloud or on-prem, an effective monitoring helps to increase the uptime by proactively notifying us of critical issues so that you resolve them before they become problems. An effective monitoring is a part of Devops process which helps you to achieve the following,</p>
<ul>
<li>A proactive approach.</li>
<li>Get visibility of your infrastructure and application issues</li>
<li>React fast to an issue and mitigate quickly.</li>
<li>Increase your application availability</li>
<li>Reduce application downtime</li>
</ul>
<p>I have been involved in lot of discussions with customers and partners on how to setup alerts in order to proactively get to know the issues and help the customers. One of the frequent questions i noticed is that about how to setup SMS alerts. In this post i wanted to cover about how to setup SMS alert on Azure at a minimal cost.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisities">PreRequisities:<a href="https://www.sajeetharan.dev/blogs/2021/01/20/2021/01/setup-sms-alerts-for-any-resource-on-azure#prerequisities" class="hash-link" aria-label="Direct link to PreRequisities:" title="Direct link to PreRequisities:">​</a></h4>
<p>You will need to have an Azure Subscription. If you do not have an Azure subscription you can simply create one with free trial.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="services-used">Services used:<a href="https://www.sajeetharan.dev/blogs/2021/01/20/2021/01/setup-sms-alerts-for-any-resource-on-azure#services-used" class="hash-link" aria-label="Direct link to Services used:" title="Direct link to Services used:">​</a></h4>
<ul>
<li>Azure Logic Apps</li>
<li>Azure Monitor</li>
<li>Twilio API</li>
<li>Azure Virtual Machine</li>
</ul>
<p>There is no SMS notification service readily available on Azure as of now. Even though <a href="https://azure.microsoft.com/en-us/services/communication-services/" target="_blank" rel="noopener noreferrer">Azure Communication Service</a> which Integrate SMS into existing applications and workflows with Azure services Logic Apps and Event Grid is still in preview and not supported in many countries. In this case you could integrate with any of the SMS providers. In this case i will use one of the famous SMS provider which i have used in many of the projects in the past.</p>
<p><strong>Step 1 :</strong> <strong>Create the Resource Group</strong></p>
<p>As the first step, we need to create the resource group that contains all the resources needed. In your case, you might already have an Azure environment with all the resources. Navigate to Azure Portal and create the resource group named&nbsp;<strong>“smsalert”</strong></p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/d311b-image-610d256958812be221537aa0a311010f.png" width="751" height="298" class="img_ev3q"></p><figcaption><p>Create Resource Group</p></figcaption></figure>
<p><strong>Step 2 : Create the application and deploy on Azure VM</strong></p>
<p>In this case, i will be focusing on setting up alerts on a Virtual Machine, If you already have an application deployed on any compute services such as AppService or AKS you could replicate the same steps. You might not need to do this step as its about application deployment. I will use the Devops starter resource to deploy a Dotnet core application and choose VM as the compute option to deploy my application.</p>
<p>Search for Devops starter in the search bar and create a new ASPNet core application and choose VM as the destination to be deployed.</p>
<figure><p><img decoding="async" loading="lazy" src="https://i2.wp.com/sajeetharan.com/wp-content/uploads/2021/02/image-1.png?fit=900%2C418&amp;ssl=1" alt="" class="img_ev3q"></p><figcaption><p>Deploy ASPNET core app using Devops starter</p></figcaption></figure>
<p>Once the application is deployed you could access the application from the url and you can login to the VM as well.</p>
<figure><p><img decoding="async" loading="lazy" src="https://i1.wp.com/sajeetharan.com/wp-content/uploads/2021/02/image-2.png?fit=900%2C541&amp;ssl=1" alt="" class="img_ev3q"></p><figcaption><p>ASPNetCore app on VM via Devops starter</p></figcaption></figure>
<p>Now we have the application deployed on VM, assume if you want to monitor the performance and setup alert whenever it breaches certain condition, lets setup azure monitor integrated with Logic apps.</p>
<p><strong>Step 2 : Create Logic app Integrated with Twilio</strong></p>
<p>You need to setup a Twilio account inorder to send the SMS alerts, the free tier gives a worth of 15$ credits which would be enough for 4000 messages. You will also get a number to send SMSes from the account portal. If you need a custom number you can set it up with extra cost.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/d509a-image-5-c90c6da46577eef1343f9f54c88e3f0f.png" width="828" height="394" class="img_ev3q"></p><figcaption><p>Twilio SMS account</p></figcaption></figure>
<p>Let's create the logic app, you can search for Logic app resource on the search bar and create a Logic app with the name smsalert under the same resource group.</p>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/1370f-image-6-e71b00bf5defd45b30b7ef06e8379003.png" width="721" height="700" class="img_ev3q"></p><figcaption><p>Logic App to send SMS alerts</p></figcaption></figure>
<p>Next step is to configure the steps in logic app , whenever a request is received from the azure monitor, we need to send the SMS to relevant members in the team which can be configured with 2 steps as below,</p>
<p>Add the first step as when an http request is received and we need to map the <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-common-schema-integrations" target="_blank" rel="noopener noreferrer">schema</a> of alert inorder to get the information from the alert and to send the sms. Paste the schema object in the request body.</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/b2f6c-image-7-18295f8b17ea3f56740dac0aa93916a7.png" width="619" height="406" class="img_ev3q"></p>
<p>Next step is to add the twilio connector inorder to send the SMS when an alert is recieved. you can configure the twilio <strong>send text message</strong> step as below, you need to pass the account SID and the access token in the configuration.</p>
<p>You can also pass a custom text which consists of any of the parameters that recieved from the alert, say for ex. CPU percentage, time etc.</p>
<figure><p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="636" height="241" class="img_ev3q"></p><figcaption><p>Twilio configuration</p></figcaption></figure>
<p>Now we are ready with the logic app integrated with Twilio, next step is to create the alert rule on the vm to send the SMS</p>
<p><strong>Step 3 : Setup Alert Rule to send SMS notification.</strong></p>
<p>Open the VM resource , on the blade navigate to Alerts and click on new alert rule, by default you can see that the resource is selected as the VM, next step is to setup the condition when you need to fire the alert, this can be a combination of multiple configurations, you can choose it from the predefined configurations. In this case i will choose the condition as "When the percentage CPU goes above 10%".</p>
<figure><p><img decoding="async" loading="lazy" src="https://i2.wp.com/sajeetharan.com/wp-content/uploads/2021/02/image-10.png?fit=900%2C261&amp;ssl=1" alt="" class="img_ev3q"></p><figcaption><p>Setup condition for Alert</p></figcaption></figure>
<figure><p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/90737-image-11-8da252533bcb5725630bf6acd4b06fcc.png" width="821" height="916" class="img_ev3q"></p><figcaption><p>Fire alert when the CPU percentage goes over 10% over a period of 1 min</p></figcaption></figure>
<p>We are good with the condition just for this demo purpose, but you can play around multiple conditions in combinationas you need for your environment.</p>
<p><strong>Step 4: Add Action Group</strong></p>
<p>In the "Add action group" section, we have to create an Action Group Name and we need to choose the Logic app as action and select the logic app which you have created in the above step,</p>
<p><img decoding="async" loading="lazy" src="https://i2.wp.com/sajeetharan.com/wp-content/uploads/2021/02/image-12.png?fit=900%2C257&amp;ssl=1" alt="" class="img_ev3q"></p>
<p>Once you are done with the action group, just pass the alert rule details and set the severity level.</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/d90fd-image-13-6372cc5ca382b5fa46defd6871ff3bf5.png" width="826" height="402" class="img_ev3q"></p>
<p>We are done with all the steps needed to send the SMS alert, now whenever the CPU usage goes above 10% the configured number will get an SMS message. If you want to send the SMS to multiple members in the team, you could just use the for condition in logic app and send it to multiple members.</p>
<p><strong>Step 5 : Manage Alert Rules</strong></p>
<p>You can also manage the alert rules based on the severity and if the action has been taken on those alerts and recrtified from the manage alerts section.</p>
<p>That's all i wanted to cover in this post, one thing to note is that i have seen many customers who already have setup email notifications via the Azure monitor, but <strong>SMS is not still readily available in all countries</strong> if you've noticed.</p>
<p>Hope this helps to setup SMS alerts on any resource that you use as compute option to run your application. Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>devops</category>
            <category>insights</category>
            <category>logicapps</category>
            <category>sms</category>
            <category>twillio</category>
        </item>
        <item>
            <title><![CDATA[Tip : Code directly in browser with Github Github Spaces]]></title>
            <link>https://www.sajeetharan.dev/blogs/2021/01/06/2021/01/vscode-instant-code-editing-codespaces</link>
            <guid>https://www.sajeetharan.dev/blogs/2021/01/06/2021/01/vscode-instant-code-editing-codespaces</guid>
            <pubDate>Wed, 06 Jan 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Exactly a year ago, Github announced codespaces and gave the option to join the beta. If you are having your repository in github and need to contribute to...]]></description>
            <content:encoded><![CDATA[<p>Exactly a year ago, Github announced <a href="https://github.com/features/codespaces" target="_blank" rel="noopener noreferrer">codespaces</a> and gave the option to join the beta. If you are having your repository in github and need to contribute to an open source project or if you want to commit something quickly to the repository this is one of the feature that you might be interested in, It supports developers to do it on the browser on any device.</p>
<p>It allows developers to use a fully-featured, cloud-hosted development environment that spins up in seconds Directly within Github. This will help you to start contributing to a project immediately from any machine, all without needing to install anything locally. If you are a developer, you should be a fan of this one. As we’ve all been adopting practices like social distancing and remote working, development teams have become more distributed. In this post, i wanted to share one of the productivity tips on how to open your code directly from the browser via codespaces.</p>
<p>You just need to open your repository and add "<strong>1s</strong>" after <strong>github</strong> when viewing the codebase on browser and github codespaces loads up instantly.</p>
<p>Here is the action below!</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/1caeb-1612892331492-1024x601-1-c2f420e5bff152bb3b8a83d495e68a73.gif" width="1024" height="601" class="img_ev3q"></p>
<p>One thing to note here is that, this feature is not directly from the Github codespaces itself, it is enabled via the <a href="https://github.com/conwnet/github1s" target="_blank" rel="noopener noreferrer">1s</a> which is sort of a middleware repository enabling this! However it's a great feature and worth exploring it!</p>
<p>Hope this enable more developers to contribute to Opensource world instantly. Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>codespaces</category>
            <category>community</category>
            <category>developers</category>
            <category>github</category>
            <category>productivity</category>
            <category>vscode</category>
        </item>
        <item>
            <title><![CDATA[Project Tye : Build developer focused Microsevices with AKS]]></title>
            <link>https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet</link>
            <guid>https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet</guid>
            <pubDate>Mon, 21 Dec 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Overview Are you are .Net developer interested in building Microservice based applications to the Cloud?. Recently i gave a talk about announcements on...]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="overview">Overview<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview">​</a></h2>
<p>Are you are .Net developer interested in building Microservice based applications to the Cloud?. Recently i gave a talk about announcements on <a href="https://www.meetup.com/Sri-Lanka-NET-Forum/events/275042627/" target="_blank" rel="noopener noreferrer">DotNet ecosystem and building Cloud Native applcitions with Tye</a> and i decided to write on the same topic . <a href="https://github.com/dotnet/tye" target="_blank" rel="noopener noreferrer">Tye</a> is an amazing project from Microsoft to ease the development, deployment with two fundamental cloud native technologies such as Docker and Kubernetes. If you have been deploying Applications in production using containers, you must be already aware of how complex steps you need to make in order to get your application running. I have worked on multiple projects where I have to run many modules as dependencies at the same time, even though I was only&nbsp; working on one of them. There has always been a requirement for a tool to start, deploy applications with a&nbsp; simple command to your desired environment without spending much time on creating docker files, configurations etc.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-project-tye">What is Project Tye?<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#what-is-project-tye" class="hash-link" aria-label="Direct link to What is Project Tye?" title="Direct link to What is Project Tye?">​</a></h2>
<p>Tye is an experimental developer tool from the .NET team at Microsoft that makes developing, testing, and deploying microservices and distributed applications easier. It comprises a local orhestrator to assist the developers to develop microservices, deploy them to kubernetes with minimal configuration and steps.</p>
<ul>
<li>Service discovery via configuration conventions makes Developers to expose their API with proper documentation</li>
<li>Add dependencies (Redis, SQL Server, etc.) without writing docker files</li>
<li>Run and debug locally using containers and Kubernetes</li>
<li>Local dashboard for metrics, logging, debugging</li>
<li>Automatically dockerize and deploy to Azure Kubernetes Service</li>
</ul>
<p>What I like really like about Project Tye is that it has a very small footprint and it is so simple to get started with after spending so many years with docker and K8s. It offers the following capabilities,</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="getting-started">Getting Started<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started">​</a></h2>
<p>Let's see how to get started with project Tye. You need to have the following Prerequisites in order to run the following application successfully.</p>
<ul>
<li>Azure Subscription (Free Trial)</li>
<li>Dotnet SDK latest</li>
<li>Visual Studio / Visual Studio Code</li>
<li>Docker/Kubernetes Extension VSCode ( Optional)</li>
</ul>
<p>You can install Project Tye as a global .NET tool. In order to install the utility, you need to run the following command in your terminal</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/7ed93-suggestion-6431de375fd131f7a9665cee6a7037d8.png" width="447" height="77" class="img_ev3q"></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet tool install -g Microsoft.Tye --version "0.2.0-alpha.20258.3"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>To verify that Tye was installed properly you can run the following command that should output the current version installed:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">&gt; tye --version</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-a-simple-application">Create a Simple Application<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#create-a-simple-application" class="hash-link" aria-label="Direct link to Create a Simple Application" title="Direct link to Create a Simple Application">​</a></h3>
<p>This section will demonstrate how to use Tye to run multi-project application.</p>
<p>Step 1 : Make a new folder named <strong>dotnetconfApp</strong></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">mkdir dotnetconfApp</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cd dotnetconfApp</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 2 : Create a frontend project with Razor</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet new razor -n frontend</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/ab17a-image-004278a173553bc7392f7504b6420d65.png" width="931" height="201" class="img_ev3q"></p>
<p>Step 3 : To run the frond end project, execute the following command</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">tye run frontend</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/bb17e-image-1-21feb9bbabbe07fcce541b4afdea522a.png" width="956" height="202" class="img_ev3q"></p>
<p>As you could see above tye will do two things: start the frontend application and run a dashboard. Navigate to&nbsp;<a href="http://localhost:8000/" target="_blank" rel="noopener noreferrer">http://localhost:8000</a>&nbsp;to see the dashboard running.</p>
<p>The dashboard should show the&nbsp;<code>frontend</code>&nbsp;application running.</p>
<ul>
<li>The&nbsp;<code>Logs</code>&nbsp;column has a link to view the streaming logs for the service.</li>
<li>the&nbsp;<code>Bindings</code>&nbsp;column has links to the listening URLs of the service.</li>
</ul>
<figure><p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="1024" height="130" class="img_ev3q"></p><figcaption><p>Project Tye Dashboard</p></figcaption></figure>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="add-multiple-projects">Add Multiple Projects<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#add-multiple-projects" class="hash-link" aria-label="Direct link to Add Multiple Projects" title="Direct link to Add Multiple Projects">​</a></h3>
<p>Step 1 : Let's go ahead and add a Web API to fetch the data for the front end application. If you haven't already, stop the existing&nbsp;<code>tye run</code>&nbsp;command using&nbsp;<code>Ctrl + C</code>. Create a backend API that the frontend will call inside of the&nbsp;<code>microservices/</code>&nbsp;folder.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet new webapi -n backend</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="961" height="136" class="img_ev3q"></p>
<p>Step 2 : Create a solution file and add both projects</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet new sln</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet sln add frontend backend</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="967" height="67" class="img_ev3q"></p>
<p>You should have a solution called&nbsp;<code>dotnetconfapp.sln</code>&nbsp;that references the&nbsp;<code>frontend</code>&nbsp;and&nbsp;<code>backend</code>&nbsp;projects.</p>
<p>Step 3: Run the multiple projects with tye . Execute the following command within the solution folder,</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">tye run</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/4d76d-image-5-1024x165-1-32d00c9494440e25d914adbb01de3323.png" width="1024" height="165" class="img_ev3q"></p>
<p>The dashboard should show both the&nbsp;<code>frontend</code>&nbsp;and&nbsp;<code>backend</code>&nbsp;services. You can navigate to both of them through either the dashboard of the url outputted by&nbsp;<code>tye run</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="make-the-communication-between-the-frontend-and-backend">Make the Communication between the frontend and backend<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#make-the-communication-between-the-frontend-and-backend" class="hash-link" aria-label="Direct link to Make the Communication between the frontend and backend" title="Direct link to Make the Communication between the frontend and backend">​</a></h3>
<p>As you see above, we have both the backend and frontend applications running, let's make them communicate. By default,&nbsp;<code>tye</code>&nbsp;enables <a href="https://github.com/dotnet/tye/blob/master/docs/reference/service_discovery.md" target="_blank" rel="noopener noreferrer">service discovery</a> by injecting environment variables with a specific naming convention.</p>
<p>Step 1: Open the solution folder with VSCode or Visual Studio</p>
<p>Step 2 : As we need to fetch and bind the data from the sample WebApi , lets add a Contract named <strong>WeatherForecast.cs</strong> to the frontend project and it should match the contract that exist in the backend project <strong>WeatherForecast.cs</strong></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">using System;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">namespace frontend</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    public class WeatherForecast</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        public DateTime Date { get; set; }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        public int TemperatureC { get; set; }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        public int TemperatureF =&gt; 32 + (int)(TemperatureC / 0.5556);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        public string Summary { get; set; }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 3: Add a file&nbsp;<code>WeatherClient.cs</code>&nbsp;to the&nbsp;<code>frontend</code>&nbsp;project with the following contents:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">using System.Net.Http;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">using System.Text.Json;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">using System.Threading.Tasks;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> namespace frontend</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     public class WeatherClient</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         private readonly JsonSerializerOptions options = new JsonSerializerOptions()</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             PropertyNameCaseInsensitive = true,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             PropertyNamingPolicy = JsonNamingPolicy.CamelCase,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         };</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         private readonly HttpClient client;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         public WeatherClient(HttpClient client)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             this.client = client;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         public async Task&lt;WeatherForecast[]&gt; GetWeatherAsync()</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             var responseMessage = await this.client.GetAsync("/weatherforecast");</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             var stream = await responseMessage.Content.ReadAsStreamAsync();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             return await JsonSerializer.DeserializeAsync&lt;WeatherForecast[]&gt;(stream, options);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 4 : Add a reference to the&nbsp;<code>Microsoft.Tye.Extensions.Configuration</code>&nbsp;package to the frontend project</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet add frontend/frontend.csproj package Microsoft.Tye.Extensions.Configuration  --version "0.4.0-*"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 5 : Register &nbsp;this client in&nbsp;<code>frontend</code>&nbsp;by adding the following to the existing&nbsp;<code>ConfigureServices</code>&nbsp;method to the existing&nbsp;<code>Startup.cs</code>&nbsp;file:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public void ConfigureServices(IServiceCollection services)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    services.AddRazorPages();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     /** Add the following to wire the client to the backend **/</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    services.AddHttpClient&lt;WeatherClient&gt;(client =&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         client.BaseAddress = Configuration.GetServiceUri("backend");</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    });</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    /** End added code **/</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This will connect the&nbsp;<code>WeatherClient</code>&nbsp;to use the correct URL for the&nbsp;<code>backend</code>&nbsp;service.</p>
<p>Step 6 : Add a&nbsp;<code>Forecasts</code>&nbsp;property to the&nbsp;<code>Index</code>&nbsp;page model under&nbsp;<code>Pages\Index.cshtml.cs</code>&nbsp;in the&nbsp;<code>frontend</code>&nbsp;project.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public WeatherForecast[] Forecasts { get; set; }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Change the&nbsp;<strong><code>OnGet</code></strong>&nbsp;method to take the&nbsp;<strong><code>WeatherClient</code></strong>&nbsp;to call the&nbsp;<code>backend</code>&nbsp;service and store the result in the&nbsp;<strong><code>Forecasts</code></strong>&nbsp;property:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">public async Task OnGet([FromServices]WeatherClient client)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     Forecasts = await client.GetWeatherAsync();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 7 : Change the&nbsp;<code>Index.cshtml</code>&nbsp;razor view to render the&nbsp;<code>Forecasts</code>&nbsp;property in the razor page:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">@page</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">@model IndexModel</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">@{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     ViewData["Title"] = "Home page";</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&lt;div class="text-center"&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    &lt;h1 class="display-4"&gt;Welcome&lt;/h1&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    &lt;p&gt;Learn about &lt;a href="https://docs.microsoft.com/aspnet/core"&gt;building Web apps with ASP.NET Core&lt;/a&gt;.&lt;/p&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">&lt;/div&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Weather Forecast:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> &lt;table class="table"&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     &lt;thead&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         &lt;tr&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;th&gt;Date&lt;/th&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;th&gt;Temp. (C)&lt;/th&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;th&gt;Temp. (F)&lt;/th&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;th&gt;Summary&lt;/th&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         &lt;/tr&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     &lt;/thead&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     &lt;tbody&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         @foreach (var forecast in @Model.Forecasts)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;tr&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 &lt;td&gt;@forecast.Date.ToShortDateString()&lt;/td&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 &lt;td&gt;@forecast.TemperatureC&lt;/td&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 &lt;td&gt;@forecast.TemperatureF&lt;/td&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 &lt;td&gt;@forecast.Summary&lt;/td&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             &lt;/tr&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">         }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     &lt;/tbody&gt;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> &lt;/table&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Step 8 : Run the project with&nbsp;<a href="https://github.com/dotnet/tye/blob/master/docs/reference/commandline/tye-run.md" target="_blank" rel="noopener noreferrer"><code>tye run</code></a>&nbsp;and the&nbsp;<code>frontend</code>&nbsp;service should be able to successfully call the&nbsp;<code>backend</code>&nbsp;service!</p>
<p>When you visit the&nbsp;<code>frontend</code>&nbsp;service you should see a table of weather data. This data was produced randomly in the&nbsp;<code>backend</code>&nbsp;service. Since you are seeing the data in a web UI in the&nbsp;<code>frontend</code>&nbsp;means that the services are able to communicate.</p>
<p>If you are getting any issues with the self signed scertifications, you need to run the below commands,</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet dev-certs https --clean</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">dotnet dev-certs https --trust</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/b8c39-image-6-1024x512-1-476c1508def20c37bfccef476be510b1.png" width="1024" height="512" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="lets-deploy-to-kubernetes">Let's deploy to Kubernetes<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#lets-deploy-to-kubernetes" class="hash-link" aria-label="Direct link to Let's deploy to Kubernetes" title="Direct link to Let's deploy to Kubernetes">​</a></h2>
<p>Step 1 : Provision the Kubernetes Cluster, since we will be using Azure Kubernetes Service , you can provision it by either <a href="https://docs.microsoft.com/en-us/azure/aks/tutorial-kubernetes-deploy-cluster" target="_blank" rel="noopener noreferrer">CLI or using Azure Portal</a></p>
<p>Step 2 : Let's authenticate and get the required credentials</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">az aks get-credentials --resource-group dotnetconfsl-rg  --name dotnetconf</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="data:image/png;base64,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" width="961" height="39" class="img_ev3q"></p>
<p>Step 3: You need to have either <a href="https://hub.docker.com/" target="_blank" rel="noopener noreferrer">Docker registry</a> or <a href="https://docs.microsoft.com/en-us/azure/aks/tutorial-kubernetes-prepare-acr" target="_blank" rel="noopener noreferrer">Azure container registry</a> created where docker images of the frontend and backend will be pushed.</p>
<p>Step 4 : Now everything is ready do easy deploy the solution. Navigate to the solution folder and execute following:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">tye deploy --interactive</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You will be prompted to enter the Container Registry (ex: 'example.azurecr.io' for Azure or 'example' for dockerhub) where the Kubernetes service is installed.</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/908ac-image-8-1024x513-1-afa617f7d59f247d133733a45f6aa742.png" width="1023" height="513" class="img_ev3q"></p>
<p>The deployment process has built the docker container and pushed repositories to my registry:</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/5eef5-image-9-3996eccdfdbec8a4854557530c15507a.png" width="996" height="329" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="test-the-application">Test the application<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#test-the-application" class="hash-link" aria-label="Direct link to Test the application" title="Direct link to Test the application">​</a></h2>
<p>If you are using VScode with the <a href="https://code.visualstudio.com/docs/azure/kubernetes" target="_blank" rel="noopener noreferrer">Kubernetes extension</a> installed, once you authenticate to Azure using <a href="https://code.visualstudio.com/docs/azure/extensions" target="_blank" rel="noopener noreferrer">Azure extension</a>, you will be able to navigate to the cluster and click on Workloads -&gt; Pods -&gt; Right Click Get</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/cb20f-image-10-1024x162-1-fe36305df815a00831545d0d37b503a2.png" width="1022" height="162" class="img_ev3q"></p>
<p>You can also explore the running pods from the Azure portal or using Cloudshell as well. You'll have two services in addition to the built-in kubernetes service.</p>
<p>You can visit the frontend application by port forwarding to the frontend service.</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/84825-image-11-85acd938fc80ee038dd84a09770aa107.png" width="751" height="134" class="img_ev3q"></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">kubectl port-forward svc/frontend 5000:80</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/fca37-image-12-715d551a5a571dcf4222d484cea17aaf.png" width="624" height="107" class="img_ev3q"></p>
<p>Now navigate to&nbsp;<a href="http://localhost:5000/" target="_blank" rel="noopener noreferrer">http://localhost:5000</a>&nbsp;to view the frontend application working on Kubernetes. You should see the list of weather forecasts just like when you were running locally.</p>
<p><strong>Some important Notes:</strong></p>
<p>⚠️ Currently tye does not provide a way to expose pods/services created to the public internet.</p>
<p>⚠️&nbsp;Currently tye does not automatically enable TLS within the cluster, and so communication takes place over HTTP instead of HTTPS.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion:<a href="https://www.sajeetharan.dev/blogs/2020/12/21/2020/12/project-tye-to-build-cloudnative-applications-with-dotnet#conclusion" class="hash-link" aria-label="Direct link to Conclusion:" title="Direct link to Conclusion:">​</a></h2>
<p>In this post I explained how easy it is to get started with&nbsp;<a href="https://github.com/dotnet/tye" target="_blank" rel="noopener noreferrer">Project Tye</a> and How to run a simple web application. You can certainly do the same adding an external dependency like SQL server or Redis cache without creating docker files manually. In short, Tye simplifies the multiple gestures for all the services within an application to a single command. Even though Project Tye is an experimental tool , you can watch out for more features around service discovery, diagnostics , observability, configuration and logging when it comes to building cloud native applications with Microservices. Certainly it's a great addition to the tooling what .Net ecosystem provides and hope you will consider exploring it more. Cheers!</p>]]></content:encoded>
            <category>azure</category>
            <category>containers</category>
            <category>debug</category>
            <category>developers</category>
            <category>docker</category>
            <category>k8s</category>
            <category>kubernetes</category>
            <category>microservices</category>
            <category>vscode</category>
        </item>
        <item>
            <title><![CDATA[Azure Tip : Opt into preview features in Azure Portal]]></title>
            <link>https://www.sajeetharan.dev/blogs/2020/12/01/2020/12/way-to-opt-into-preview-features-in-azure</link>
            <guid>https://www.sajeetharan.dev/blogs/2020/12/01/2020/12/way-to-opt-into-preview-features-in-azure</guid>
            <pubDate>Tue, 01 Dec 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[One of the hardest truth is that even as Microsoft employee, i have become very difficult to catch up with Azure updates. It can be said that Azure is...]]></description>
            <content:encoded><![CDATA[<p>One of the hardest truth is that even as Microsoft employee, i have become very difficult to catch up with Azure updates. It can be said that Azure is constantly evolving day by day.</p>
<p>There’s always a lot of new services and products being offered through Azure, and some of them go into preview before being GA (General Availability).</p>
<p>There are two types of previews in Azure:</p>
<ul>
<li><strong>Private Preview</strong>. An Azure feature marked “private preview” is available to&nbsp;<em>specific</em> Azure customers for evaluation purposes.</li>
<li><strong>Public Preview</strong>. An Azure feature marked “public preview” is available to&nbsp;<em>all</em> Azure customers for evaluation purposes.</li>
</ul>
<p>One of the ways to check for preview features is that , if you browse to the <a href="https://azure.microsoft.com/en-us/updates/?status=inpreview" target="_blank" rel="noopener noreferrer">Azure Updates portal</a>, you can see all new features order per date and not only you can filter for the ones that are in preview, but you can also do a Keyword search.</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/b0cf0-snippet-24a172873fca3c68aab52678cdbfbf55.png" width="1224" height="823" class="img_ev3q"></p>
<p>However, today i noticed a new feature in the azure portal where you can opt into previews right there. You just need to navigate to the subscriptions blade , choose your subscription and click on preview features&nbsp;for your subscription as shown in the image below,</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/7e2dc-tip-b2543a5b4b6b2036942f3f3276256aa2.gif" width="1409" height="868" class="img_ev3q"></p>
<p>It's a great way to explore the new features, always keep yourself updated with what’s coming for Azure, but more importantly, provide as much feedback as you can. Cheers!</p>
<p>Hope this helps!</p>]]></content:encoded>
            <category>azure-tip-developer-portal-preview</category>
        </item>
        <item>
            <title><![CDATA[Azure Tip : Learn Azure Modules while you're in Azure Portal]]></title>
            <link>https://www.sajeetharan.dev/blogs/2020/11/02/2020/11/azure-tip-learn-modules-while-youre-in-azure-portal</link>
            <guid>https://www.sajeetharan.dev/blogs/2020/11/02/2020/11/azure-tip-learn-modules-while-youre-in-azure-portal</guid>
            <pubDate>Mon, 02 Nov 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Starting as a fresher in Azure can be difficult because you don't have any previous knowledge regarding Azure and the services that it offers. If you are...]]></description>
            <content:encoded><![CDATA[<p>Starting as a fresher in Azure can be difficult because you don't have any previous knowledge regarding Azure and the services that it offers. If you are new to Azure and exploring on azure portal, One of the tips that I wanted to share today with azure enthusiasts is that you can access the <a href="https://aka.ms/learn" target="_blank" rel="noopener noreferrer">learn Modules</a> while you are in <a href="http://portal.azure.com/" target="_blank" rel="noopener noreferrer">Azure Portal</a>. You can navigate to the service that you want to create and navigate to the links provided next to each service, here is a view,</p>
<p><img decoding="async" loading="lazy" src="https://www.sajeetharan.dev/assets/images/49e08-tip-1-35115a03c368bed1cd3e7e8c17961450.gif" width="511" height="714" class="img_ev3q"></p>
<p>Hope this helps!</p>]]></content:encoded>
            <category>azure</category>
            <category>azure-tip</category>
            <category>mslearn</category>
        </item>
    </channel>
</rss>