<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Cloud AI Fusion]]></title><description><![CDATA[Cloud AI Fusion]]></description><link>https://www.cloudaifusion.com</link><image><url>https://substackcdn.com/image/fetch/$s_!0NPR!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F041fadd1-4f30-410c-8da0-f6961c318571_1024x1024.png</url><title>Cloud AI Fusion</title><link>https://www.cloudaifusion.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 18 Apr 2026 17:08:57 GMT</lastBuildDate><atom:link href="https://www.cloudaifusion.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Cloud AI Fusion]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[cloudaifusion@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[cloudaifusion@substack.com]]></itunes:email><itunes:name><![CDATA[Andy Brough]]></itunes:name></itunes:owner><itunes:author><![CDATA[Andy Brough]]></itunes:author><googleplay:owner><![CDATA[cloudaifusion@substack.com]]></googleplay:owner><googleplay:email><![CDATA[cloudaifusion@substack.com]]></googleplay:email><googleplay:author><![CDATA[Andy Brough]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Giving Architects Superpowers on Every Terraform PR]]></title><description><![CDATA[Because reviewing raw HCL is not an architectural review]]></description><link>https://www.cloudaifusion.com/p/giving-architects-superpowers-on</link><guid isPermaLink="false">https://www.cloudaifusion.com/p/giving-architects-superpowers-on</guid><dc:creator><![CDATA[Andy Brough]]></dc:creator><pubDate>Sat, 18 Apr 2026 11:36:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R_rp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R_rp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R_rp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 424w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 848w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 1272w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R_rp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png" width="1456" height="1337" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1337,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:221725,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194497753?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R_rp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 424w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 848w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 1272w, https://substackcdn.com/image/fetch/$s_!R_rp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cddebf4-8ecd-4c02-bf9c-6482b13c51d1_1472x1352.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Last week I wrote about <a href="https://www.cloudaifusion.com/p/architecture-drift-using-claude-code">using Claude Code to generate Draw.io architecture diagrams directly from Terraform</a>. The idea was simple: instead of maintaining diagrams by hand  which nobody does consistently &#8212; let the AI generate them from the source of truth.</p><p>The response I got most often was: <em>&#8220;That&#8217;s great, but you&#8217;re still comparing them manually, right? Isn&#8217;t that the hard part?&#8221;</em></p><p>They&#8217;re not wrong. So I kept going.</p><p>But before I get into the technical details, I want to be clear about what this is actually for &#8212; because it&#8217;s easy to frame this as a documentation automation story, and that undersells it.</p><div><hr></div><h2>The real problem: architects can&#8217;t review what they can&#8217;t see</h2><p>When a Terraform PR lands for review, the people best placed to assess its architectural implications &#8212; the principal engineers, the solutions architects, the team leads &#8212; are looking at raw HCL. They&#8217;re expected to mentally reconstruct what the infrastructure looks like, what&#8217;s changing, and whether those changes introduce risk. For anything beyond a trivial PR, that&#8217;s an unreasonable ask.</p><p>So what actually happens? The code gets reviewed for syntax and convention. Someone checks the variable names and the resource tags. The architectural implications &#8212; the ones that matter &#8212; get a cursory glance at best. Problems that should be caught at PR time surface weeks later, in production.</p><p>This isn&#8217;t a people problem. It&#8217;s a tooling problem. Architects can&#8217;t review what they can&#8217;t see.</p><div><hr></div><h2>What this workflow does</h2><p>This is a GitHub Actions workflow that automatically updates your AWS architecture diagram and posts a structured risk analysis to every Terraform PR &#8212; giving architects the visual context and the flagged risks they need to do a proper review.</p><p>Every time a PR touches your Terraform files, the reviewer gets:</p><ul><li><p>A visual diagram of the updated architecture &#8212; what the infrastructure looks like <em>after</em> this PR merges, committed directly to the branch as a Draw.io file and an inline PNG</p></li><li><p>A risk analysis with HIGH / MEDIUM / LOW severity flags on the architectural implications of each change</p></li><li><p>A resource table showing what changed, the service&#8217;s role, and the impact &#8212; split by change type (modified, force-replaced, permanently deleted)</p></li></ul><p>The architect&#8217;s job isn&#8217;t replaced &#8212; it&#8217;s made possible. This is a task that needs both data processing and contextual understanding, and that&#8217;s precisely where AI and human capability complement each other. The workflow handles the data &#8212; diffing infrastructure, classifying changes, flagging risks. The architect brings what AI can&#8217;t: experience, intuition, and the judgement to understand nuance. One without the other is weaker. Together, they&#8217;re more capable than either alone.</p><div><hr></div><h2>What the PR comment looks like</h2><p>Two real examples from the same system &#8212; a Document Management Service running on ECS Fargate with RDS and S3. One PR strengthens the security posture, one weakens it. The difference in what the architect sees is stark.</p><h3>Example 1: WAF added &#8212; security posture strengthened</h3><p>A PR adds a WAF Web ACL, attaches it to the ALB, and wires up access logging to CloudWatch. Four resources added, zero removed, no risks flagged.</p><h2>&#127959;&#65039; AWS Architecture Review</h2><p><strong>4 resource(s) changed</strong> &#8212; 4 added/modified, 0 removed</p><h2>Resources added</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tz9x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tz9x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 424w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 848w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 1272w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tz9x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png" width="950" height="326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:326,&quot;width&quot;:950,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37583,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194497753?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tz9x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 424w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 848w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 1272w, https://substackcdn.com/image/fetch/$s_!Tz9x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62c352a-0461-484c-ba0f-2c1e26d99429_950x326.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jjde!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jjde!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 424w, https://substackcdn.com/image/fetch/$s_!jjde!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 848w, https://substackcdn.com/image/fetch/$s_!jjde!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 1272w, https://substackcdn.com/image/fetch/$s_!jjde!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jjde!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png" width="1384" height="884" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:884,&quot;width&quot;:1384,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96504,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194497753?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jjde!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 424w, https://substackcdn.com/image/fetch/$s_!jjde!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 848w, https://substackcdn.com/image/fetch/$s_!jjde!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 1272w, https://substackcdn.com/image/fetch/$s_!jjde!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c4c26de-0f49-4f89-bfca-3e27fb46413f_1384x884.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>&#128214; <a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/github/workflow/aws-architecture-sync/docs/withwaf/architecture.md">View companion guide</a> </p><div><hr></div><p>The architect can see at a glance that this is a clean security improvement. Every added resource has a clear role, nothing is being removed, and there are no risks to assess. The review is quick and confident.</p><p>The companion guide tells the full story &#8212; the updated network topology, the new request flow through WAF before the ALB, the CloudWatch log group for threat analysis, and the security implications of each addition. An architect joining the team after this PR can understand the full security model without having to read the Terraform.</p><p>If you want to see exactly what change produced this output, the <a href="https://github.com/cloudaifusion/sdlc-automation/tree/main/examples/github/workflow/aws-architecture-sync/terraform/aws/withwaf">Terraform is in the examples repo</a> &#8212; the <strong>withwaf</strong> folder shows the full infrastructure definition including all four WAF resources. It&#8217;s a useful reference for understanding the relationship between the HCL and what the workflow surfaces to the architect.</p><h3>Example 2: WAF removed &#8212; security posture weakened</h3><p>Now the same WAF resources are deleted in a PR. This time the workflow fires HIGH and MEDIUM severity flags, and the architect has decisions to make before this merges.</p><h2>&#127959;&#65039; AWS Architecture Review</h2><p><strong>4 resource(s) changed</strong> &#8212; 1 added/modified, 3 removed</p><h3>&#9888;&#65039; Architecture Risks</h3><ul><li><p><strong>HIGH &#8212; WAF Web ACL deleted (</strong><code>dms-production-waf</code><strong>)</strong>: All inbound HTTP traffic now reaches the ALB unfiltered. OWASP managed rules (SQLi, XSS, known bad IPs) that were blocking threats at the edge are gone. Any application-layer exploit protection previously handled by WAF must now be handled entirely at the application level.</p></li><li><p><strong>MEDIUM &#8212; WAF access logs deleted (</strong><code>aws-waf-logs-dms-production</code><strong>)</strong>: Loss of allow/block decision logs and source IP visibility that was used for threat analysis. Incident response for web-layer attacks will have a significant blind spot.</p></li></ul><h2>Resources modified (in-place)</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0xJl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0xJl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 424w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 848w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 1272w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0xJl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png" width="1030" height="120" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1030,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14824,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194497753?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0xJl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 424w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 848w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 1272w, https://substackcdn.com/image/fetch/$s_!0xJl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe923f10d-5a65-4b51-bcb4-7649c29e8b43_1030x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h2>Resources permanently deleted</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HmHc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HmHc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 424w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 848w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 1272w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HmHc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png" width="1026" height="233" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:233,&quot;width&quot;:1026,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35611,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194497753?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HmHc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 424w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 848w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 1272w, https://substackcdn.com/image/fetch/$s_!HmHc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f77d83f-59d6-41ae-bbe7-9da8fbe3f21f_1026x233.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>&#128214; <a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/github/workflow/aws-architecture-sync/docs/withoutwaf/architecture.md">View companion guide</a> </p><div><hr></div><p>This is exactly the scenario where the workflow earns its place. Without it, a reviewer looking at the raw Terraform diff sees four resource deletions and has to mentally reconstruct what each one does and what disappears with it. With the workflow, the architect sees two flagged risks in plain English &#8212; the ALB is now unfiltered, and threat visibility is gone &#8212; before a single approval is clicked.</p><p>The <a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/github/workflow/aws-architecture-sync/docs/withoutwaf/architecture.md">companion guide</a> shows the updated architecture without the WAF layer, making the exposure immediately visible. The architect can now make an informed decision: is this intentional? Is there a compensating control? Should this block the merge?</p><p>That&#8217;s the conversation this workflow is designed to start.</p><p>The <a href="https://github.com/cloudaifusion/sdlc-automation/tree/main/examples/github/workflow/aws-architecture-sync/terraform/aws/withoutwaf">Terraform for this example is also in the examples repo</a> &#8212; the <strong>withoutwaf</strong> folder shows the same infrastructure with the WAF resources removed. Compare it with the <strong>withwaf</strong> folder to see precisely what four resource deletions look like in raw HCL versus what they look like to an architect reviewing a PR comment.</p><div><hr></div><h2>How it works</h2><p>When a PR is opened against any file under <strong>infra/terraform/aws/</strong>:</p><ol><li><p>A <strong><a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/scripts/get_diff.py">Python script</a></strong> diffs the branch against main and produces a <strong>diff.json</strong> of added, modified, and deleted AWS resources</p></li><li><p><strong>Claude Code</strong> runs the <strong><a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/.claude/skills/aws-architecture-sync/SKILL.md">aws-architecture-sync</a></strong> skill, which orchestrates the <strong><a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/.claude/skills/aws-architecture-diagram/SKILL.md">aws-architecture-diagram</a></strong> skill to update the diagram and regenerate the companion guide</p></li><li><p>The updated files are committed back to the PR branch</p></li><li><p>A PR comment is posted with the risk analysis, resource tables, diagram PNG, and links</p></li></ol><p>Two Claude Code skills power this under the hood. The <strong><a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/.claude/skills/aws-architecture-sync/SKILL.md">aws-architecture-sync</a></strong> skill analyses the Terraform diff, determines which nodes and edges need adding or removing, and produces the risk summary that lands in the PR comment. The <strong><a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/.claude/skills/aws-architecture-diagram/SKILL.md">aws-architecture-diagram</a></strong> skill owns all the Draw.io XML generation &#8212; looking up accurate AWS service icons, applying layout rules, writing the <code>.drawio</code> file, and generating the companion guide. Both skills live as Markdown files in <strong>.claude/skills/</strong> inside the <a href="https://github.com/cloudaifusion/sdlc-automation">cloudaifusion/sdlc-automation</a> repo, which is public and forkable. The <a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/scripts/get_diff.py">Python diff script</a> and a <a href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/github/workflow/aws-architecture-sync/aws-architecture-sync.yml">full example workflow</a> are also in the repo.</p><div><hr></div><h2>Setting it up</h2><h3>Prerequisites</h3><ul><li><p>A GitHub repository with Terraform files</p></li><li><p>One of the following for Claude AI access:</p><ul><li><p><strong>Anthropic API key</strong> &#8212; individuals or small teams getting started; pay-as-you-go with no subscription required</p></li><li><p><strong>Claude.ai OAuth token</strong> &#8212; teams already on a Claude.ai Pro or Team subscription who want to get more value from it beyond the chat interface</p></li><li><p><strong>AWS Bedrock</strong> &#8212; organisations that need data to stay within a specific AWS region (data residency requirements), want Claude usage billed through their existing AWS account rather than a separate Anthropic account, or need to integrate with IAM, VPCs, or AWS-native security controls. More setup overhead, but the right choice for enterprise environments where the primary focus is enterprise-grade security, compliance, and integration within an existing AWS ecosystem.</p></li></ul></li></ul><h3>Step 1 &#8212; Create a docs folder</h3><p>Create an empty <code>docs/</code> folder in your repo so the workflow has somewhere to write the diagram:</p><pre><code><code>mkdir docs
touch docs/.gitkeep
git add docs/.gitkeep
git commit -m "Add docs folder for architecture diagrams"
</code></code></pre><h3>Step 2 &#8212; Fork the repo and create the workflow file</h3><p>First, fork <a href="https://github.com/cloudaifusion/sdlc-automation">cloudaifusion/sdlc-automation</a> to your own GitHub org. This gives you full control &#8212; you own the skills, the workflow, and the scripts, and can customise them to match your own conventions without depending on this repo being maintained.</p><p>Then create <strong>.github/workflows/aws-architecture-sync.yml</strong> in your infrastructure repo, pointing the <strong>uses</strong> line at your fork:</p><pre><code><code>name: AWS Architecture Sync

on:
  pull_request:
    paths:
      - 'infra/terraform/aws/**'   # adjust to match your Terraform path
  workflow_dispatch:

jobs:
  architecture-review:
    uses: your-org/sdlc-automation/.github/workflows/aws-architecture-sync.yml@main
    permissions:
      contents: write
      pull-requests: write
      id-token: write
    with:
      terraform_path: infra/terraform/aws   # adjust to your Terraform path
      docs_path: docs
      diagram_name: architecture
      pr_number: ${{ github.event.pull_request.number }}
    secrets:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
</code></code></pre><p>Replace <code>your-org</code> with your GitHub org or username. Adjust <strong>terraform_path</strong> to wherever your <strong>.tf</strong> files live. The workflow accepts these inputs if your repo structure differs from the defaults:</p><ul><li><p><strong>terraform_path</strong> (default: <strong>infra/terraform/aws</strong>): Path to your <code>.</code><strong>tf</strong> files</p></li><li><p><strong>docs_path</strong> (default: <strong>docs</strong>): Where to write the diagram and guide</p></li><li><p><strong>diagram_name</strong> (default: <strong>architecture</strong>): Base filename for the outputs</p></li></ul><h3>Step 3 &#8212; Add your secret</h3><p>Go to your GitHub repo &#8594; Settings &#8594; Secrets and variables &#8594; Actions &#8594; New repository secret</p><p>Add one of:</p><ul><li><p><strong>ANTHROPIC_API_KEY</strong>: Your key from console.anthropic.com</p></li><li><p><strong>CLAUDE_CODE_OAUTH_TOKEN</strong>: Your Claude.ai OAuth token</p></li></ul><p>The workflow will use whichever is available. The OAuth token takes priority.</p><h3>Step 4 &#8212; Trigger it</h3><p>Make any change to a file under your terraform_path and open a PR. The workflow will:</p><ul><li><p>Diff the Terraform changes against main</p></li><li><p>Generate or update docs/architecture.drawio, docs/architecture.md, and docs/architecture.png</p></li><li><p>Commit those files back to your PR branch</p></li><li><p>Post a comment on the PR with the diagram and a summary of what changed</p></li></ul><p>The first time it runs with no existing diagram, it generates one from scratch from all your current Terraform files. On every subsequent PR it updates incrementally based on the diff.</p><h3>Step 5 &#8212; View the diagram locally</h3><p>Install the <a href="https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio">Draw.io Integration extension</a> in VS Code, pull the branch, and open docs/architecture.drawio. It renders as a fully interactive diagram, useful for deeper review sessions where the architect wants to explore the full picture rather than just the diff.</p><div><hr></div><h2>A note on prompt injection</h2><p>The workflow passes your Terraform files and existing diagram XML directly into the Claude prompt. Any text in those files is treated as data, not instructions &#8212; the prompt wraps each input in explicit BEGIN DATA / END DATA delimiters and opens with a system directive telling Claude to ignore any commands embedded in data sections. If you&#8217;re running this against a repo with external contributors, this is the relevant threat model to be aware of.</p><div><hr></div><h2>A note on CI errors you can safely ignore</h2><p>You may see these messages in the workflow logs:</p><pre><code><code>Failed to connect to the bus: Could not parse server address...
Exiting GPU process due to errors during initialization</code></code></pre><p>These come from Draw.io (an Electron app) running headlessly in CI without a desktop session. They don&#8217;t affect the output &#8212; as long as you see PNG export succeeded at the end, everything worked.</p><div><hr></div><h2>Optional: AWS Bedrock instead of direct API</h2><p>If you want the full step-by-step guide to configuring Bedrock access from GitHub Actions, I've covered that in detail in <a href="https://www.cloudaifusion.com/p/calling-aws-bedrock-from-github-actions">Calling AWS Bedrock from GitHub Actions Without Storing Credentials</a>. The summary below covers the key variables you'll need once that's set up.</p><p>If you want to use AWS Bedrock to call Claude &#8212; for data residency or cost billing reasons &#8212; add these GitHub repository variables:</p><ul><li><p><strong>AWS_ROLE_ARN</strong>: e.g. arn:aws:iam::123456789:role/github-actions-role</p></li><li><p><strong>AWS_REGION</strong>: e.g. eu-west-2</p></li><li><p><strong>BEDROCK_MODEL_ID</strong>: e.g. eu.anthropic.claude-sonnet-4-6</p></li><li><p><strong>USE_BEDROCK</strong>: true</p></li></ul><h3>Configuring GitHub OIDC trust for AWS Bedrock</h3><p>GitHub Actions can assume an AWS IAM role without storing long-lived credentials, using OpenID Connect (OIDC). Here&#8217;s how to set it up.</p><p><strong>1 &#8212; Add GitHub as an OIDC identity provider in AWS</strong></p><ul><li><p>Open the AWS IAM console &#8594; Identity providers &#8594; Add provider</p></li><li><p>Select OpenID Connect and set:</p><ul><li><p><strong>Provider URL</strong>: https://token.actions.githubusercontent.com</p></li><li><p><strong>Audience</strong>: sts.amazonaws.com</p></li></ul></li><li><p>Click <strong>Add provider</strong> &#8212; AWS now handles the thumbprint automatically</p></li></ul><p><strong>2 &#8212; Create the IAM role</strong></p><ul><li><p>Go to IAM &#8594; Roles &#8594; Create role</p></li><li><p>Select <strong>Web identity</strong> as the trusted entity type</p></li><li><p>Set the following fields:</p><ul><li><p><strong>Identity provider</strong>: token.actions.githubusercontent.com</p></li><li><p><strong>Audience</strong>: sts.amazonaws.com</p></li><li><p><strong>GitHub organization</strong>: Your GitHub org or username</p></li><li><p><strong>GitHub repository</strong>: The repo where your Terraform lives and your workflow runs, or * for all repos in the org</p></li><li><p><strong>GitHub branch</strong>: Leave as * to allow any branch, or specify a branch to restrict further</p></li></ul></li></ul><blockquote><p><strong>Important</strong>: the GitHub repository field should be the repo that contains your Terraform files and your workflow file &#8212; not the sdlc-automation repo you forked. The trust policy needs to match the repo that is actually making the AWS API calls. If you're using a reusable workflow defined in another repo, the trust policy still needs to reference your infrastructure repo, not the one where the reusable workflow lives.</p></blockquote><p>AWS will generate the trust policy condition automatically from these fields.</p><ul><li><p>Click <strong>Next</strong> &#8212; AWS will take you to the Add permissions screen</p></li><li><p>On the Add permissions screen, click <strong>Next</strong> again without selecting anything &#8212; you&#8217;ll add the Bedrock policy as an inline policy after the role is created</p></li><li><p>On the Name, review, and create screen, verify the auto-generated trust policy contains sts:AssumeRoleWithWebIdentity and the correct repo condition</p></li><li><p>Give the role a name (e.g. github-actions-bedrock) and click <strong>Create role</strong></p></li></ul><p><strong>3 &#8212; Add the Bedrock permission policy</strong></p><p>Once the role is created, open it and go to the <strong>Permissions</strong> tab &#8594; <strong>Add permissions</strong> &#8594; <strong>Create inline policy</strong>, switch to the <strong>JSON</strong> editor and paste the following:</p><p>json</p><pre><code><code>{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBedrockInvoke",
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": [
        "arn:aws:bedrock:*::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:*:*:inference-profile/*"
      ]
    }
  ]
}</code></code></pre><p>The inference-profile resource is needed if you use cross-region inference profiles (e.g. eu.anthropic.claude-sonnet-4-6). If you want to allow invocation of any Bedrock model rather than restricting to Claude, you can simplify the resource to &#8220;Resource&#8221;: &#8220;*&#8221;.</p><p>Click <strong>Next</strong>, give the policy a name (e.g. github-actions-bedrock-policy), and click <strong>Create policy</strong>.</p><p><strong>4 &#8212; Verify the trust policy</strong></p><p>On the role&#8217;s Trust relationships tab, confirm it contains sts:AssumeRoleWithWebIdentity with a condition scoped to your repo. If it doesn&#8217;t look right, edit it directly in the console before proceeding.</p><p><strong>5 &#8212; Copy the role ARN and add it to GitHub</strong></p><ul><li><p>On the role summary page, copy the ARN (e.g. arn:aws:iam::123456789012:role/github-actions-bedrock)</p></li><li><p>Go to your GitHub repo &#8594; Settings &#8594; Secrets and variables &#8594; Actions &#8594; <strong>Variables</strong> tab &#8594; <strong>New repository variable</strong></p></li><li><p>Add the following repository variables:</p><ul><li><p><strong>AWS_ROLE_ARN</strong>: The ARN you just copied</p></li><li><p><strong>AWS_REGION</strong>: e.g. eu-west-2</p></li><li><p><strong>BEDROCK_MODEL_ID</strong>: e.g. eu.anthropic.claude-sonnet-4-6</p></li><li><p><strong>USE_BEDROCK</strong>: true</p></li></ul></li></ul><p>These are <strong>repository variables</strong> (referenced in workflows as vars.AWS_ROLE_ARN), not environment variables. GitHub Actions environment variables are scoped to specific deployment environments like production or staging &#8212; repository variables are available to all workflows in the repo.</p><p><strong>6 &#8212; Complete the Anthropic first-time use form</strong></p><p>AWS has retired the Model Access page &#8212; serverless foundation models are now automatically available without manual enablement. However, Anthropic models still require a one-time use case form before first invocation:</p><ul><li><p>Open the Amazon Bedrock console &#8594; <strong>Model catalog</strong></p></li><li><p>Select any Anthropic Claude model</p></li><li><p>Complete the first-time use form and submit &#8212; access is granted immediately</p></li></ul><p>This only needs to be done once per AWS account. If you are using AWS Organizations, completing it at the management account level covers all child accounts.</p><p>Once this is done, the workflow will authenticate to AWS via OIDC on each run, assume the role, and call Bedrock &#8212; no stored credentials required.</p><div><hr></div><h2>Cost</h2><p>Each PR run makes one Claude API call using claude-sonnet-4-6. The cost per run is low &#8212; a few cents at most for a typical Terraform diff &#8212; and a fraction of what an architectural issue caught in production rather than at review would cost. Your actual cost will vary depending on diagram size and the number of resources changed.</p><div><hr></div><h2>Customising for your own conventions</h2><p>The skills are just Markdown files &#8212; fork <a href="https://github.com/cloudaifusion/sdlc-automation">cloudaifusion/sdlc-automation</a>, edit the aws-architecture-sync/SKILL.md or aws-architecture-diagram/SKILL.md files in .claude/skills/ to match your conventions, then point your workflow at your fork:</p><p>yaml</p><pre><code><code>uses: your-org/sdlc-automation/.github/workflows/aws-architecture-sync.yml@main</code></code></pre><div><hr></div><h2>The broader point</h2><p>Good architectural governance doesn&#8217;t fail because architects don&#8217;t care. It fails because the feedback loop is too slow and the context too hard to assemble. By the time an architectural concern surfaces through the usual channels, the code has shipped, the infrastructure is running, and the cost of change is an order of magnitude higher.</p><p>Putting a visual architecture review directly in the PR &#8212; at the moment the change is being made, with risks already flagged and explained &#8212; closes that loop. It gives architects the right information at the right time, and it makes proper architectural review a natural part of the PR process rather than an afterthought.</p><p>The full source is at <a href="https://github.com/cloudaifusion/sdlc-automation">github.com/cloudaifusion/sdlc-automation</a>.</p>]]></content:encoded></item><item><title><![CDATA[Calling AWS Bedrock from GitHub Actions Without Storing Credentials]]></title><description><![CDATA[How to use OIDC to give your workflows secure, keyless access to Claude and any other Bedrock model]]></description><link>https://www.cloudaifusion.com/p/calling-aws-bedrock-from-github-actions</link><guid isPermaLink="false">https://www.cloudaifusion.com/p/calling-aws-bedrock-from-github-actions</guid><dc:creator><![CDATA[Andy Brough]]></dc:creator><pubDate>Mon, 13 Apr 2026 11:31:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0eEL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0eEL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0eEL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 424w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 848w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 1272w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0eEL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png" width="717" height="610" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:610,&quot;width&quot;:717,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51922,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0eEL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 424w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 848w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 1272w, https://substackcdn.com/image/fetch/$s_!0eEL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66b9b8c4-a62a-44f0-a149-210a20824d8e_717x610.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you&#8217;re running Claude in GitHub Actions via the Anthropic API, the setup is straightforward &#8212; add an API key as a GitHub secret and you&#8217;re done. But in enterprise environments that&#8217;s often not an option. Your security policy requires AWS. Your compliance framework mandates data residency. Your billing needs to flow through a single AWS account. Or you simply want Claude to live inside the same security perimeter as the rest of your infrastructure.</p><p>That&#8217;s where AWS Bedrock comes in. And the right way to connect GitHub Actions to Bedrock isn&#8217;t to store AWS credentials as secrets &#8212; it&#8217;s to use OpenID Connect (OIDC) so your workflows can assume an IAM role directly, with no long-lived credentials anywhere.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.cloudaifusion.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Cloud AI Fusion! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I&#8217;ll use Claude as the example throughout, but the pattern works for any model you&#8217;re invoking through Bedrock.</p><div><hr></div><h2>Why OIDC and not stored credentials</h2><p>The traditional approach &#8212; creating an IAM user, generating an access key, and storing it as a GitHub secret &#8212; works, but it has real problems:</p><ul><li><p>Long-lived credentials that need rotating</p></li><li><p>Credentials that exist outside AWS, in GitHub&#8217;s secret store</p></li><li><p>No straightforward way to scope them to a specific repo or workflow</p></li><li><p>An audit trail that doesn&#8217;t cleanly tie API calls back to individual workflow runs</p></li></ul><p>OIDC solves all of this. GitHub acts as an identity provider, and each workflow run gets a short-lived token that it exchanges for temporary AWS credentials. The credentials are scoped to the role, the role is scoped to the repo, and nothing sensitive is stored anywhere. When the workflow finishes, the credentials expire.</p><p>It&#8217;s the same pattern AWS recommends for any CI/CD system, and it&#8217;s what you should be using if you&#8217;re running anything production-grade through GitHub Actions.</p><div><hr></div><h2>What you&#8217;re building</h2><p>By the end of this post you&#8217;ll have:</p><ul><li><p>GitHub Actions workflows that can call AWS Bedrock without any stored AWS credentials</p></li><li><p>An IAM role scoped to your specific repo, assumable only by GitHub Actions</p></li><li><p>A Bedrock permission policy that follows least privilege</p></li><li><p>Claude (or any Bedrock model) callable from any workflow in your repo</p></li></ul><div><hr></div><h2>Step 1 &#8212; Add GitHub as an OIDC identity provider in AWS</h2><p>This tells AWS to trust tokens issued by GitHub Actions. You only need to do this once per AWS account.</p><ul><li><p>Open the AWS IAM console &#8594; Identity providers &#8594; Add provider</p></li><li><p>Select <strong>OpenID Connect</strong> and set:</p><ul><li><p><strong>Provider URL</strong>: https://token.actions.githubusercontent.com</p></li></ul></li><li><ul><li><p><strong>Audience</strong>: <code>sts.amazonaws.com</code></p></li></ul></li><li><p>Click <strong>Add provider</strong> &#8212; AWS now handles the thumbprint automatically</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9FMl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9FMl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 424w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 848w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 1272w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9FMl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png" width="1112" height="752" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:752,&quot;width&quot;:1112,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97230,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9FMl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 424w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 848w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 1272w, https://substackcdn.com/image/fetch/$s_!9FMl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8dda2ec-da40-4f93-a1cc-c5e5cb78c602_1112x752.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Once this is done, any GitHub Actions workflow can potentially request AWS credentials &#8212; but only if an IAM role explicitly trusts it, which is what the next step controls.</p><div><hr></div><h2>Step 2 &#8212; Create the IAM role</h2><p>This role is what your GitHub Actions workflow will assume. The trust policy restricts it to your specific repo.</p><ul><li><p>Go to IAM &#8594; Roles &#8594; Create role</p></li><li><p>Select <strong>Web identity</strong> as the trusted entity type</p></li><li><p>Set the following fields:</p><ul><li><p><strong>Identity provider</strong>: <code>token.actions.githubusercontent.com</code></p></li><li><p><strong>Audience</strong>: <code>sts.amazonaws.com</code></p></li><li><p><strong>GitHub organization</strong>: Your GitHub org or username (e.g. <code>cloudaifusion</code>)</p></li><li><p><strong>GitHub repository</strong>: The repo where your Terraform lives and your workflow runs (e.g. <code>my-infrastructure-repo</code>), or <code>*</code> for all repos in the org</p></li><li><p><strong>GitHub branch</strong>: Leave as <code>*</code> to allow any branch, or specify a branch to restrict further</p></li></ul></li></ul><blockquote><p><strong>Important</strong>: this should be the repo that contains your Terraform files and your workflow file &#8212; the repo that is actually making the AWS API calls. If you&#8217;re using a reusable workflow from another repo, the trust policy still needs to reference your repo, not the one where the reusable workflow is defined.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2CDa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2CDa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 424w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 848w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 1272w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2CDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png" width="1113" height="1171" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/53393806-549d-46de-a603-e707967a12ff_1113x1171.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1171,&quot;width&quot;:1113,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:141473,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!2CDa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 424w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 848w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 1272w, https://substackcdn.com/image/fetch/$s_!2CDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53393806-549d-46de-a603-e707967a12ff_1113x1171.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>AWS will generate the trust policy condition automatically from these fields &#8212; you no longer need to add it manually.</p><ul><li><p>Click <strong>Next</strong> &#8212; AWS will take you to the Add permissions screen</p></li><li><p>On the Add permissions screen, click <strong>Next</strong> again without selecting anything &#8212; you&#8217;ll add the Bedrock policy as an inline policy after the role is created</p></li></ul><ul><li><p>AWS will show you a <strong>Name, review, and create</strong> screen. Before creating the role:</p><ul><li><p>Enter a role name (e.g. <code>github-actions-bedrock</code>)</p></li><li><p>Review the auto-generated trust policy under <strong>Step 1: Select trusted entities</strong> &#8212; confirm it contains <code>sts:AssumeRoleWithWebIdentity</code> and the correct repo condition</p></li><li><p>Optionally add tags under <strong>Step 3: Add tags</strong></p></li></ul></li><li><p>Click <strong>Create role</strong></p></li></ul><div><hr></div><h2>Step 3 &#8212; Add the Bedrock permission policy</h2><p>Once the role is created, open it and add an inline policy:</p><ul><li><p>Go to the <strong>Permissions</strong> tab &#8594; <strong>Add permissions</strong> &#8594; <strong>Create inline policy</strong></p></li><li><p>Switch to the <strong>JSON</strong> editor and paste the following:</p></li></ul><pre><code><code>{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBedrockInvoke",
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": [
        "arn:aws:bedrock:*::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:*:*:inference-profile/*"
      ]
    }
  ]
}
</code></code></pre><ul><li><p>Click <strong>Next</strong>, give the policy a name (e.g. <code>github-actions-bedrock-policy</code>), and click <strong>Create policy</strong></p></li></ul><p>A few things worth noting here:</p><ul><li><p><strong>bedrock:InvokeModel</strong> covers standard synchronous calls; <strong>bedrock:InvokeModelWithResponseStream</strong> covers streaming responses &#8212; include both unless you&#8217;re certain you won&#8217;t need streaming</p></li><li><p>The <strong>foundation-model</strong> ARN pattern scopes access to Anthropic Claude models only. Tighten to a specific model ARN if you want to restrict further (e.g. <strong>arn:aws:bedrock:eu-west-2::foundation-model/anthropic.claude-sonnet-4-6</strong>)</p></li><li><p>The <strong>inference-profile</strong> resource is required if you&#8217;re using cross-region inference profiles (e.g. <strong>eu.anthropic.claude-sonnet-4-6</strong>) &#8212; these route requests across regions for resilience and Bedrock requires the profile ARN to be explicitly permitted</p></li></ul><p>If you want to allow invocation of any Bedrock model rather than restricting to Claude, you can simplify the resource to <code>"</code><strong>Resource": "*"</strong>. This is less restrictive but easier to maintain if your model requirements change over time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yfYw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yfYw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 424w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 848w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 1272w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yfYw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png" width="1123" height="825" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:825,&quot;width&quot;:1123,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:95906,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yfYw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 424w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 848w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 1272w, https://substackcdn.com/image/fetch/$s_!yfYw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586c038e-c6ed-4489-ae0f-2969b1a93724_1123x825.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Step 4 &#8212; Verify the trust policy</h2><p>On the role&#8217;s Trust relationships tab, confirm it looks like this:</p><pre><code><code>{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:YOUR_ORG/YOUR_REPO:*"
        }
      }
    }
  ]
}
</code></code></pre><p>If it doesn&#8217;t match this structure, edit it directly in the console before proceeding.</p><div><hr></div><h2>Step 5 &#8212; Complete the Anthropic first-time use form</h2><p>AWS has retired the Model Access page &#8212; serverless foundation models are now automatically available in your account without any manual enablement step.</p><p>However, Anthropic models are an exception. Before you can invoke any Claude model via Bedrock, Anthropic requires a one-time use case form to be completed. This only needs to be done once per AWS account (or once at the organisation management account level, which then covers all child accounts).</p><p>To complete it:</p><ul><li><p>Open the Amazon Bedrock console</p></li><li><p>Go to <strong>Model catalog</strong> and select any Anthropic Claude model</p></li><li><p>You will be prompted to submit use case details &#8212; fill in the form and submit</p></li><li><p>Access is granted immediately once the form is successfully submitted</p></li></ul><blockquote><p>If you are using AWS Organizations, completing the form at the management account level via the API covers all child accounts automatically &#8212; you won&#8217;t need to repeat it per account.</p></blockquote><div><hr></div><h2>Step 6 &#8212; Add the role ARN to GitHub</h2><ul><li><p>On the role summary page in IAM, copy the ARN (e.g. <strong>arn:aws:iam::123456789012:role/github-actions-bedrock</strong>)</p></li><li><p>Go to your GitHub repo &#8594; Settings &#8594; Secrets and variables &#8594; Actions &#8594; <strong>Variables</strong> tab &#8594; <strong>New repository variable</strong></p></li><li><p>Add the following repository variables:</p><ul><li><p><strong>AWS_ROLE_ARN:</strong> The ARN you just copied</p></li><li><p><strong>AWS_REGION:</strong> The region your Bedrock models are in, e.g. <strong>eu-west-2</strong></p></li><li><p><strong>BEDROCK_MODEL_ID:</strong> The model you want to invoke, e.g. <strong>eu.anthropic.claude-sonnet-4-6</strong></p></li></ul></li></ul><p>These are <strong>repository variables</strong> (referenced in workflows as <code>vars.AWS_ROLE_ARN</code>), not environment variables. GitHub Actions environment variables are scoped to specific deployment environments like <code>production</code> or <code>staging</code> &#8212; repository variables are available to all workflows in the repo.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tx2E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tx2E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 424w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 848w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 1272w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tx2E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png" width="558" height="230" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a592c043-05ea-44e9-bce2-a5653afed62e_558x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:230,&quot;width&quot;:558,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12491,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tx2E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 424w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 848w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 1272w, https://substackcdn.com/image/fetch/$s_!Tx2E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa592c043-05ea-44e9-bce2-a5653afed62e_558x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h2>Step 7 &#8212; Configure your workflow</h2><p>Create the file <strong>.github/workflows/my-workflow.yml</strong> in your repo. If the <code>.github/workflows/</code> directory doesn&#8217;t exist yet, create it:</p><pre><code><code>mkdir -p .github/workflows
touch .github/workflows/my-workflow.yml
</code></code></pre><p>Then add the following to the file:</p><pre><code><code>name: My Workflow

on:
  pull_request:

jobs:
  my-job:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write   # required for OIDC

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ vars.AWS_ROLE_ARN }}
          aws-region: ${{ vars.AWS_REGION }}

      - name: Call Bedrock
        env:
          BEDROCK_MODEL_ID: ${{ vars.BEDROCK_MODEL_ID }}
          AWS_REGION: ${{ vars.AWS_REGION }}
        run: |
          pip install boto3
          python scripts/call_bedrock.py
</code></code></pre><p>Commit and push the file to your repo:</p><pre><code><code>git add .github/workflows/my-workflow.yml
git commit -m "Add Bedrock workflow"
git push
</code></code></pre><p>The workflow will trigger on every pull request. If you want to test it manually before opening a PR, add <strong>workflow_dispatch:</strong> to the <strong>on:</strong> block &#8212; this adds a <strong>Run workflow</strong> button in the GitHub Actions tab.</p><p>The <strong>id-token: write</strong> permission is what allows the workflow to request an OIDC token from GitHub. Without it, the <strong>configure-aws-credentials</strong> action will fail. The rest is handled automatically &#8212; the action exchanges the OIDC token for temporary AWS credentials and sets them as environment variables for subsequent steps.</p><blockquote><p><strong>Using a reusable workflow?</strong> If you&#8217;re calling a reusable workflow (e.g. one shared across repos via <strong>uses: your-org/your-repo/.github/workflows/my-workflow.yml@main)</strong>, the <strong>aws-actions/configure-aws-credentials</strong> step is likely already handled inside the reusable workflow itself. In that case you don&#8217;t need to add it here &#8212; just pass the <strong>aws_role_arn</strong>, <strong>aws_region</strong>, and any other Bedrock inputs as <code>with</code> parameters to the reusable workflow and let it handle the rest. Check the reusable workflow&#8217;s documentation to confirm.</p></blockquote><div><hr></div><h2>Creating the script</h2><p>Create <strong>scripts/call_bedrock.py</strong> in your repo &#8212; this is the script the workflow calls:</p><pre><code><code>import boto3
import json
import os

bedrock = boto3.client("bedrock-runtime", region_name=os.environ["AWS_REGION"])

response = bedrock.invoke_model(
    modelId=os.environ["BEDROCK_MODEL_ID"],
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": [
            {"role": "user", "content": "who was the last person to walk on the moon"}
        ]
    })
)

result = json.loads(response["body"].read())
print(result["content"][0]["text"])
</code></code></pre><p>No API keys. No secrets. The boto3 client picks up the temporary credentials that <strong>configure-aws-credentials</strong> set as environment variables, and Bedrock handles the rest. Replace <code>"</code><strong>who was the last person to walk on the moon</strong><code>"</code> with whatever you want Claude to do.</p><p>Your repo structure should look like this:</p><pre><code><code>your-repo/
&#9500;&#9472;&#9472; scripts/
&#9474;   &#9492;&#9472;&#9472; call_bedrock.py
&#9492;&#9472;&#9472; .github/
    &#9492;&#9472;&#9472; workflows/
        &#9492;&#9472;&#9472; my-workflow.yml
</code></code></pre><blockquote><p><strong>Using Claude Code CLI instead of boto3?</strong> If you&#8217;re running agentic tasks with the <strong>claude</strong> CLI rather than making direct API calls, the approach is slightly different. After the <strong>configure-aws-credentials</strong> step, set <strong>CLAUDE_CODE_USE_BEDROCK=1</strong> as an environment variable and pass <strong>--model</strong> with your Bedrock model ID:</p><pre><code><code>export CLAUDE_CODE_USE_BEDROCK=1
claude -p "who was the last person to walk on the moon" --model eu.anthropic.claude-sonnet-4-6
</code></code></pre><p>The CLI picks up the AWS credentials from the environment automatically &#8212; no script needed.</p></blockquote><div><hr></div><h2>Step 8 &#8212; Trigger it with a PR</h2><p>Make a small change on a new branch and open a PR to trigger the workflow:</p><pre><code><code>git checkout -b test/bedrock-oidc
echo "# test" &gt;&gt; README.md
git add README.md
git commit -m "Test Bedrock OIDC workflow"
git push -u origin test/bedrock-oidc
</code></code></pre><p>Then open a PR from <code>test/bedrock-oidc</code> into <code>main</code> on GitHub. The workflow will trigger automatically.</p><p>To watch it run:</p><ul><li><p>Go to your repo &#8594; <strong>Actions</strong> tab</p></li><li><p>Select <strong>My Workflow</strong> from the left sidebar</p></li><li><p>Click the running workflow to see the live logs</p></li></ul><p>A successful run will show the <strong>Configure AWS credentials via OIDC</strong> step completing without errors, followed by the <strong>Call Bedrock</strong> step printing Claude&#8217;s response to the logs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zo2D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zo2D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 424w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 848w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 1272w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zo2D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png" width="1190" height="437" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:437,&quot;width&quot;:1190,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38204,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zo2D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 424w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 848w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 1272w, https://substackcdn.com/image/fetch/$s_!zo2D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c7255fb-c8e9-4ac9-991c-d24d7d500661_1190x437.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If something goes wrong, the logs will tell you which step failed &#8212; check the troubleshooting section below for the most common errors.</p><div><hr></div><h2>How this compares to storing credentials</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1qTR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1qTR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 424w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 848w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 1272w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1qTR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png" width="705" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:705,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32570,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/194055359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1qTR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 424w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 848w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 1272w, https://substackcdn.com/image/fetch/$s_!1qTR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F438e1ed6-9e6a-4e23-ad85-20584b139c25_705x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The one-time setup cost of OIDC pays for itself immediately in reduced credential management overhead and a significantly better security posture.</p><div><hr></div><h2>Troubleshooting</h2><p><strong>Error assuming role: Not authorized to perform sts:AssumeRoleWithWebIdentity</strong> The trust policy condition doesn&#8217;t match the workflow&#8217;s subject claim. Check that the GitHub organization and repository in the trust policy exactly match your repo name, including case.</p><p><strong>id-token: write permission missing</strong> The workflow job must include <code>id-token: write</code> in its permissions block. If you&#8217;ve set top-level permissions in the workflow, make sure <code>id-token: write</code> is included there too.</p><p><strong>Could not load credentials from any providers</strong> The <code>configure-aws-credentials </code>step didn&#8217;t run, failed silently, or the credentials expired before the Bedrock call. Check that the step ran successfully and that your Bedrock call happens in the same job.</p><p><strong>You don't have access to the model with the specified model ID</strong> The Anthropic first-time use form hasn&#8217;t been completed for this AWS account. Go back to Step 5 and complete the form via the Bedrock model catalog &#8212; access is granted immediately on submission.</p><p><strong>not available on your bedrock (Claude Code CLI)</strong> The model ID specified via <strong>--model</strong> isn&#8217;t available in the region you&#8217;re using. Check that the cross-region inference profile ID matches your <strong>AWS_REGION</strong> prefix (e.g. <strong>eu.anthropic.claude-sonnet-4-6 for eu-west-2</strong>) and that the Anthropic FTU form has been completed.</p><div><hr></div><h2>The broader point</h2><p>Storing credentials is the path of least resistance, but it&#8217;s also the path of most risk. OIDC gives you a cleaner security model, a better audit trail, and no credentials to rotate or accidentally expose &#8212; with a setup cost that&#8217;s a few hours at most.</p><p>If you&#8217;re running Claude or any other model through Bedrock in a production environment, this is the setup you should have. The pattern is the same regardless of which model you&#8217;re invoking or what your workflow is doing with it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.cloudaifusion.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Cloud AI Fusion! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Architecture Drift: Using Claude Code to Keep Your Terraform Honest]]></title><description><![CDATA[What if your Terraform could draw its own architecture diagram?]]></description><link>https://www.cloudaifusion.com/p/architecture-drift-using-claude-code</link><guid isPermaLink="false">https://www.cloudaifusion.com/p/architecture-drift-using-claude-code</guid><dc:creator><![CDATA[Andy Brough]]></dc:creator><pubDate>Mon, 30 Mar 2026 15:27:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4f9c1738-745e-46ed-bf5a-1e15cd60d702_1200x627.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Snls!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Snls!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 424w, https://substackcdn.com/image/fetch/$s_!Snls!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 848w, https://substackcdn.com/image/fetch/$s_!Snls!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 1272w, https://substackcdn.com/image/fetch/$s_!Snls!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Snls!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png" width="1200" height="627" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:627,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:187536,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Snls!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 424w, https://substackcdn.com/image/fetch/$s_!Snls!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 848w, https://substackcdn.com/image/fetch/$s_!Snls!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 1272w, https://substackcdn.com/image/fetch/$s_!Snls!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f40da5-1be6-497f-9f75-9f3c7e790c25_1200x627.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>This is the first in a series exploring how AI is changing the Software Development Lifecycle &#8212; from requirements and design through to deployment and operations. My focus is practical and production-grounded: tools and patterns that actually work, not just ones that look good in a demo.</em></p><div><hr></div><p>There&#8217;s a version of your infrastructure that lives in a diagram. Clean boxes, neat arrows, everything labelled the way you intended it. And then there&#8217;s the version that actually exists in your Terraform &#8212; the one that&#8217;s been through six sprints, two engineers, a production incident, and a cost-optimisation review.</p><p>These two versions start the same. They rarely stay that way.</p><div><hr></div><h3>The Problem: Architecture Drift Is Invisible Until It Isn&#8217;t</h3><p>When I hand off an architecture diagram to a DevOps team, I&#8217;m communicating intent. This is what we&#8217;re building. Here&#8217;s how the components relate. Here&#8217;s the security boundary. The Terraform that comes back usually reflects that intent - at least initially.</p><p>But Terraform evolves. It has to. Requirements change, new services get added, existing resources get refactored or replaced. And crucially, these changes don&#8217;t automatically flow back into the architecture diagram. The diagram sits in a Confluence page or a Draw.io file somewhere, quietly becoming fiction.</p><p>This matters more than it might seem. Architecture diagrams aren&#8217;t just documentation artefacts - they&#8217;re the shared mental model that engineers, architects, and technical stakeholders use to reason about a system. When they diverge from reality, decisions get made on false assumptions. Security reviews miss components that have been added. Onboarding takes longer. Incident response gets harder.</p><p>The technical term for this is <strong>infrastructure drift</strong>, but the diagram problem is subtler than the classic &#8220;drift from desired state&#8221; that tools like <code>terraform plan</code> catch. No tool natively tells you: <em>your diagram no longer reflects your code</em>. You have to figure that out yourself &#8212; and typically you only discover it when it matters most.</p><p>I&#8217;ve been looking for a practical way to close this loop for a while. The approach I&#8217;ve landed on &#8212; using a Claude Code skill to reverse-engineer Draw.io diagrams directly from Terraform &#8212; is the most useful solution I&#8217;ve found.</p><div><hr></div><h3>The Tool: A Claude Code Skill for AWS Architecture Diagrams</h3><p>The skill is open source, published here: &#128279; <a href="https://github.com/oharu121/oharu-commands-skills-gems/tree/main/skills/aws-architecture-diagram">https://github.com/oharu121/oharu-commands-skills-gems/tree/main/skills/aws-architecture-diagram</a></p><p>The reference article that explains the thinking behind it is worth reading too: &#128279; <a href="https://dev.classmethod.jp/en/articles/claude-code-skill-aws-architecture-diagram/">https://dev.classmethod.jp/en/articles/claude-code-skill-aws-architecture-diagram/</a></p><p>What it does is straightforward but genuinely useful: it teaches Claude Code to produce two outputs - a Draw.io-compatible XML diagram using accurate AWS service icons, and a markdown file describing the architecture. The markdown alone is useful as a living summary of what your infrastructure actually contains.</p><p><strong>Installing it on Windows</strong> takes about two minutes:</p><ol><li><p>Clone the repository: </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">git clone https://github.com/oharu121/oharu-commands-skills-gems.git</code></pre></div></li><li><p>Copy the <code>skills/aws-architecture-diagram</code> folder into your <code>%USERPROFILE%\.claude\skills folder</code></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">xcopy /E /I oharu-commands-skills-gems\skills\aws-architecture-diagram "%USERPROFILE%\.claude\skills\aws-architecture-diagram"</code></pre></div></li></ol><ol start="3"><li><p>Give Claude Code permission to read all of the files in its skills folder to prevent it from asking permission to read reference files every time you use the skill. This is done by editing Claudes settings.json file:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">notepad %USERPROFILE%\.claude\settings.json</code></pre></div><p>and adding the line: </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">"Read(~/.claude/skills/**)"</code></pre></div><p>For example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{

  "permissions": {
    "allow": [
      "Read(~/.claude/skills/**)"
    ]
  }
}</code></pre></div></li></ol><p><strong>Using it is straightforward</strong>: Prompt claude to generate an AWS architecture diagram by pointing it at a folder of Terraform files:</p><pre><code><code>create an aws architecture diagram from the files in the terraform folder</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pGYS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pGYS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 424w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 848w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 1272w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pGYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png" width="712" height="453" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:712,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35288,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pGYS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 424w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 848w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 1272w, https://substackcdn.com/image/fetch/$s_!pGYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd317bd5f-63ec-4af9-9b61-451a3b3ffac1_712x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That&#8217;s it.</p><div><hr></div><h3>A Real Example: Two Audiences, One Codebase</h3><p>I ran this against a set of <a href="https://github.com/cloudaifusion/sdlc-automation/tree/main/claude/skills/aws-architecture-diagram/terraform/aws">Terraform files</a> to test something specific: whether the skill could adapt its output for different audiences. I asked for two versions of the diagram using only a small prompt change.</p><p><strong>Prompt 1 - non technical audience:</strong></p><blockquote><p><em>create an aws architecture diagram from the files in the terraform/aws folder for a non technical audience</em></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/three-tier-web-app.drawio" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cZ-x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 424w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 848w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 1272w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cZ-x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png" width="1456" height="809" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:144023,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/three-tier-web-app.drawio&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cZ-x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 424w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 848w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 1272w, https://substackcdn.com/image/fetch/$s_!cZ-x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f0e44d-8a77-4261-8a16-cf501c7a2478_1621x901.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Non-technical view &#8212; click to open the Draw.io file</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/three-tier-web-app.md" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m2s_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 424w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 848w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 1272w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m2s_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png" width="1091" height="738" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:738,&quot;width&quot;:1091,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:89829,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/three-tier-web-app.md&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m2s_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 424w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 848w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 1272w, https://substackcdn.com/image/fetch/$s_!m2s_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d62e08-8cfb-4275-ba92-a57aadef1def_1091x738.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Architecture markdown &#8212; click to open the full description</em></figcaption></figure></div><p><strong>Prompt 2 - technical audience:</strong></p><blockquote><p><em>create an aws architecture diagram from the files in the terraform/aws folder for a technical audience</em></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/dms-production-fargate.drawio" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DDi6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 424w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 848w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 1272w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DDi6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png" width="1156" height="801" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:801,&quot;width&quot;:1156,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:142996,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/dms-production-fargate.drawio&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DDi6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 424w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 848w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 1272w, https://substackcdn.com/image/fetch/$s_!DDi6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8c59b26-239b-4276-98c3-68ca9c4366fc_1156x801.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Non-technical view &#8212; click to open the Draw.io file</em></figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/dms-production-fargate.md" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6jVY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 424w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 848w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 1272w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6jVY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png" width="1227" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1227,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:129057,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://github.com/cloudaifusion/sdlc-automation/blob/main/examples/claude/skills/aws-architecture-diagram/docs/dms-production-fargate.md&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192531672?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6jVY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 424w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 848w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 1272w, https://substackcdn.com/image/fetch/$s_!6jVY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d4d676c-c0a7-49bd-b391-80366c4c233d_1227x936.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Architecture markdown &#8212; click to open the full description</figcaption></figure></div><p>The difference is striking. The non-technical version strips away ARNs, resource identifiers, and implementation detail - leaving a clean, readable view of the system&#8217;s shape. The technical version exposes the detail that an engineer needs: resource names, relationships, configuration specifics. Same infrastructure, two genuinely different perspectives, generated from the same prompt pattern with a single word changed.</p><p>This matters in practice. One of the friction points in architecture work is producing documentation at the right level for the right audience. Generating both from code - rather than maintaining them separately - removes a real overhead.</p><div><hr></div><h3>How I&#8217;m Incorporating This Into My Workflow</h3><p>The most immediate use case for me is <strong>architecture verification</strong>. Before a significant release, or when onboarding to a codebase I haven&#8217;t touched in a while, I&#8217;ll run this against the current Terraform and compare the output against the original design. It&#8217;s not a binary pass/fail check &#8212; it&#8217;s a conversation starter. <em>What changed? Was that intentional? Does the current state still reflect the system we meant to build?</em></p><p>I&#8217;m also planning to use it as part of <strong>design reviews</strong>. When a DevOps engineer proposes infrastructure changes, generating a diagram from their Terraform branch gives me something concrete to review - not just code, but a visual representation of the architectural impact of those changes. That&#8217;s a much richer review surface.</p><p>Longer term, I think there&#8217;s something interesting in running this on a cadence - generating a diagram from Terraform on every merge to main and storing it alongside the code. Not as a replacement for maintained architecture documentation, but as an automatically-updated snapshot that at least answers the question: <em>what does this infrastructure look like right now?</em></p><div><hr></div><h3>Where It Falls Short</h3><p>In the spirit of being practical rather than promotional: this tool isn&#8217;t magic, and it has real limits.</p><p>It works from what Terraform can see. If your architecture involves manual resources, console-configured components, or multi-repo infrastructure that isn&#8217;t referenced in the folder you point it at, those won&#8217;t appear. The diagram reflects the code, not necessarily the full system.</p><p>The quality of output also depends on how well-structured your Terraform is. Highly modular, well-named code produces clearer diagrams. Sprawling, inconsistently named legacy Terraform produces noisier output. Garbage in, garbage out - but that&#8217;s also a useful signal in itself.</p><p>And Draw.io is not everyone&#8217;s preferred diagramming tool. If your team lives in Lucidchart or Miro, you&#8217;ll need to export and convert. That&#8217;s a friction point worth noting.</p><div><hr></div><h3>The Bigger Picture</h3><p>What I find genuinely exciting about this approach isn&#8217;t just the specific tool &#8212; it&#8217;s what it represents. The idea that infrastructure code can be a <em>source of truth</em> for architecture diagrams, rather than the other way around, is a meaningful shift. For too long, diagrams have been upstream artefacts that drift from reality. Turning Terraform into the source and generating the diagram from it inverts that relationship in a useful way.</p><p>Claude Code skills are still relatively new territory. But this use case - using an AI coding agent to bridge the gap between code and visual architecture understanding - is exactly the kind of workflow augmentation I&#8217;ll be returning to throughout this series.</p><p>If you work with AWS infrastructure and Terraform, it&#8217;s worth twenty minutes to try it. The install is trivial, the prompt is simple, and the output is immediately useful.</p><div><hr></div><p>The Terraform files used in this example are available here: <a href="https://github.com/cloudaifusion/sdlc-automation">https://github.com/cloudaifusion/sdlc-automation</a></p><p>f you found this useful, subscribe to catch the next one.</p><p></p>]]></content:encoded></item><item><title><![CDATA[I once led a dev team of 12. After a few weeks with Claude Code, I’m not so sure what that means anymore]]></title><description><![CDATA[A practitioner&#8217;s honest account of what changes &#8212; and what doesn&#8217;t &#8212; when you start working alongside an AI that reasons about architecture.]]></description><link>https://www.cloudaifusion.com/p/i-once-led-a-dev-team-of-12-after</link><guid isPermaLink="false">https://www.cloudaifusion.com/p/i-once-led-a-dev-team-of-12-after</guid><dc:creator><![CDATA[Andy Brough]]></dc:creator><pubDate>Tue, 24 Mar 2026 10:45:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5TMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5TMn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5TMn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5TMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5TMn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!5TMn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F966a8a65-aefc-4a17-9595-9a38ef9f853d_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">team of 12 software developers becoming a team of 1 using AI</figcaption></figure></div><p></p><p>I recently completed <em><a href="https://www.coursera.org/learn/claude-code">Claude Code: Software Engineering with Generative AI Agents</a></em> on Coursera &#8212; a five-hour course that turned out to be one of the more practically useful things I&#8217;ve done this year. I went in as someone already working with AI workflows. I came out genuinely rethinking what a single developer or small team can realistically build.</p><p>The course doesn&#8217;t dwell on theory &#8212; it&#8217;s hands-on from the start: setting up projects, delegating to agents, iterating, debugging, and managing increasingly complex systems.</p><p><strong>What struck me first: code quality</strong></p><p>Not just &#8220;working&#8221; code, but well-structured, readable, and aligned with the standards I&#8217;d normally expect from experienced engineers. The technical depth is where the course earns its credibility.</p><p>Using claude.md to define project context and standards, driving consistent behaviour with Claude commands, integrating directly into a Git-based workflow. The section on parallel development with Git worktrees was particularly striking &#8212; multiple agents working simultaneously on different features or fixes, without stepping on each other.</p><p><strong>From impressive demo to something I rely on</strong></p><p>Since finishing the course, I&#8217;ve been using Claude Code to explore and evolve architectural patterns &#8212; clean architecture, modular monolith, vertical slice &#8212; and it&#8217;s been remarkably effective at maintaining boundaries, generating consistent modules, and staying coherent as complexity increases.</p><p>That&#8217;s the part that moved it from &#8220;impressive demo&#8221; to something I am now starting to rely on.</p><p><em>Claude isn&#8217;t better autocomplete. It behaves more like a collaborative engineer &#8212; reasoning about architecture, writing meaningful tests, refactoring codebases, contributing to design decisions. The experience is closer to orchestrating a group of capable junior-to-mid engineers than using an AI assistant.</em></p><p><strong>Who this is for</strong></p><p>For anyone familiar with AI tools but unsure how to bring them into real engineering practice: this course is a good place to start. Not because it promises some future where AI writes all your code, but because it shows &#8212; concretely, right now &#8212; how to work alongside it in ways that actually shift what&#8217;s possible.</p><p>The team-of-12 question isn&#8217;t rhetorical. I&#8217;m still working through what it means &#8212; for how teams are structured, how work gets scoped, and what &#8220;senior engineering judgement&#8221; looks like when the execution layer becomes this capable.</p><p><em>The next post in this series goes deeper into the architectural patterns I&#8217;ve been testing with Claude Code &#8212; what held up, what didn&#8217;t, and what surprised me.</em></p>]]></content:encoded></item><item><title><![CDATA[Most OAuth bugs are design mistakes — made before the first line of code is written]]></title><description><![CDATA[A two-question decision guide for picking the right flow, every time.]]></description><link>https://www.cloudaifusion.com/p/most-oauth-bugs-are-design-mistakes</link><guid isPermaLink="false">https://www.cloudaifusion.com/p/most-oauth-bugs-are-design-mistakes</guid><dc:creator><![CDATA[Andy Brough]]></dc:creator><pubDate>Wed, 18 Mar 2026 09:45:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Pjce!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pjce!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pjce!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pjce!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg" width="1080" height="1350" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1350,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:131148,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.cloudaifusion.com/i/192627095?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Pjce!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Pjce!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff62fa413-474b-43e7-82e5-a64cf9a5a426_1080x1350.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>After 21+ years building and architecting software systems, one pattern keeps showing up in security reviews: OAuth is implemented incorrectly more often than correctly &#8212; and almost always because the wrong flow was chosen at the start.</p><p>Not because developers don&#8217;t understand OAuth. Because there are too many flows, most documentation assumes context you don&#8217;t have, and the wrong choice isn&#8217;t obvious until something breaks in production.</p><p>Here&#8217;s the decision guide I use. Two questions. That&#8217;s it.</p><p><strong>Question 1: Is a user signing in?</strong></p><blockquote><p>&#8594; <strong>No &#8594; Client Credentials flow.</strong> Your app authenticates as itself. No redirect, no user consent, no browser. Use this for service-to-service and machine-to-machine calls.</p><p>&#8594; <strong>Yes &#8594; </strong>Go to Question 2.</p></blockquote><p><strong>Question 2: What type of application is calling the API?</strong></p><blockquote><p>&#8594; <strong>Web app with a backend &#8594; Authorization Code flow.</strong> The client secret never leaves your server. The code exchange happens server-to-server.</p><p>&#8594; <strong>SPA with no secret-holding backend &#8594; Authorization Code + PKCE.</strong> No long-lived secret required. This replaces the deprecated Implicit flow &#8212; don&#8217;t use Implicit.</p><p>&#8594; <strong>Native mobile or desktop app &#8594; Authorization Code + PKCE.</strong> No embedded secrets in the app package. Redirects are handled by the OS.</p><p>&#8594; <strong>CLI or headless device &#8594; Device Code flow.</strong> Users visit a short URL and enter a code while the device polls for authentication. Purpose-built for no-browser environments.</p></blockquote><p>One thing most OAuth guides quietly skip:</p><p><strong>Your API doesn&#8217;t choose the flow.</strong> It validates Bearer tokens (RFC 6750). The flow is chosen by whoever calls the API. This matters architecturally &#8212; it means your API is flow-agnostic by design.</p><p>The fundamental split behind all of this is simple: <strong>confidential clients</strong> (web apps with a backend) can store a secret securely. <strong>Public clients</strong> (SPAs, native apps, CLIs) cannot. PKCE exists precisely because of that gap &#8212; it prevents authorization code interception attacks without requiring a stored secret.</p><p>OAuth isn&#8217;t conceptually hard. It gets complicated when the wrong flow is chosen upfront. Run the two questions before writing a line of auth code and you&#8217;ll eliminate most of the bugs before they&#8217;re possible.</p><p></p>]]></content:encoded></item></channel></rss>