<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vivek V.</title>
    <description>The latest articles on DEV Community by Vivek V. (@vivek-aws).</description>
    <link>https://dev.to/vivek-aws</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2942908%2F7ad76ec4-a4a7-4f5b-ab60-577c34fe4c7b.jpg</url>
      <title>DEV Community: Vivek V.</title>
      <link>https://dev.to/vivek-aws</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vivek-aws"/>
    <language>en</language>
    <item>
      <title>I Crashed My Mac 5 Times So You Don't Have To: Mounting S3 Files on macOS</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Fri, 10 Apr 2026 05:46:45 +0000</pubDate>
      <link>https://dev.to/aws-heroes/i-crashed-my-mac-5-times-so-you-dont-have-to-mounting-s3-files-on-macos-3nmp</link>
      <guid>https://dev.to/aws-heroes/i-crashed-my-mac-5-times-so-you-dont-have-to-mounting-s3-files-on-macos-3nmp</guid>
      <description>&lt;p&gt;Two days ago, AWS launched &lt;a href="https://aws.amazon.com/s3/features/files/" rel="noopener noreferrer"&gt;S3 Files&lt;/a&gt; — a managed NFS layer that turns any S3 bucket into a mountable filesystem. Sub-millisecond latency within AWS. Full read/write. Bidirectional sync. The AWS community collectively lost its mind, and rightfully so.&lt;/p&gt;

&lt;p&gt;There's just one problem: it only works on AWS compute. EC2, Lambda, EKS, ECS. Not your Mac. Not your laptop. Not the machine where you actually write code.&lt;/p&gt;

&lt;p&gt;I spent the last 48 hours fixing that. Along the way, I kernel-panicked my MacBook five times, got "access denied" in three different ways, discovered a crash bug in &lt;code&gt;efs-proxy&lt;/code&gt;, and eventually built a tool that mounts S3 Files on macOS with two commands. This is the story of everything that went wrong, and the one thing that finally worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;As Corey Quinn &lt;a href="https://www.lastweekinaws.com/blog/s3-is-not-a-filesystem-but-now-theres-one-in-front-of-it/" rel="noopener noreferrer"&gt;put it&lt;/a&gt;, S3 has never been a filesystem — but now there's a real one sitting in front of it. Andy Warfield's team didn't just bolt a POSIX layer onto S3 and call it a day. They built a proper filesystem backed by EFS infrastructure, with S3 as the durable source of truth.&lt;/p&gt;

&lt;p&gt;Think of S3 Files as another tier in the S3 hierarchy — a file system front end for hot, frequently accessed data that needs mutation, user interaction, or low-latency access. You create a file system on any bucket or prefix with no data migration. Your existing S3 data is immediately visible as files and folders.&lt;/p&gt;

&lt;p&gt;The smart defaults are what make it feel magical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metadata pre-warms instantly.&lt;/strong&gt; When you create a file system, all S3 key prefixes are mapped to directories and files. &lt;code&gt;ls&lt;/code&gt; works immediately — no waiting. This is a massive differentiator from FUSE-based tools like Mountpoint, where &lt;code&gt;ls&lt;/code&gt; on a large dataset can take &lt;em&gt;minutes&lt;/em&gt; because it does a HEAD or LIST call per object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small files (under 128KB) auto-sync on directory access.&lt;/strong&gt; When you &lt;code&gt;cd&lt;/code&gt; into a directory, code files, configs, and small assets are pulled into the fast tier automatically. No explicit fetch needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large files stream directly from S3.&lt;/strong&gt; Files over 128KB are lazy-loaded on first read, and very large files may be served directly from S3's throughput layer without ever being copied into the file system tier. This is the ReadBypass optimization in &lt;code&gt;efs-proxy&lt;/code&gt; — designed for EC2, but as we'll see, it doesn't play well with our non-standard Docker + NLB setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Changes sync back to S3 approximately every minute. Changes to S3 objects sync into the file system via EventBridge notifications. Data expires from the fast tier after 30 days by default (configurable) and rehydrates on next access.&lt;/p&gt;

&lt;p&gt;AWS explicitly positions agentic AI as a first-class use case — multi-step, multi-process workloads where agents need to share state, read reference data, and produce outputs collaboratively. That's exactly the use case that got me excited enough to spend 48 hours making this work on a Mac.&lt;/p&gt;

&lt;p&gt;And here's something that doesn't get enough credit: &lt;strong&gt;S3 Files shipped with Day 1 CloudFormation support&lt;/strong&gt; (&lt;code&gt;AWS::S3Files::FileSystem&lt;/code&gt; and &lt;code&gt;AWS::S3Files::MountTarget&lt;/code&gt;). CDK works via L1 constructs — no native L2 constructs yet, but you can provision everything from IaC on Day 1. Our entire CDK stack — VPC, bucket, IAM role, S3 Files filesystem, mount target, NLB — deploys in one command. That's rare for a new AWS service these days. But what about local development? What about editing S3-backed files in VS Code on your Mac? What about &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;echo "hello" &amp;gt; file.txt&lt;/code&gt; from your terminal?&lt;/p&gt;

&lt;p&gt;That's what I wanted. A native Mac folder backed by S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: macOS Can't Speak S3 Files
&lt;/h2&gt;

&lt;p&gt;S3 Files requires three things that macOS cannot provide:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;NFSv4.2&lt;/strong&gt; — macOS ships with NFSv4.0. The NFS client is baked into the kernel. You can't upgrade it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS encryption&lt;/strong&gt; — S3 Files rejects every unencrypted NFS connection. No exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM authentication&lt;/strong&gt; — Every mount requires an EFS RPC Bind handshake with AWS credentials, handled by a binary called &lt;code&gt;efs-proxy&lt;/code&gt; (part of &lt;a href="https://github.com/aws/efs-utils" rel="noopener noreferrer"&gt;&lt;code&gt;amazon-efs-utils&lt;/code&gt;&lt;/a&gt;). This only runs on Linux.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three hard requirements. Zero macOS support. Let's see how many ways this can fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 1: Native macOS NFS Mount → 💀 Kernel Panic (x5)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq64qj3jgtipwqvkuktmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq64qj3jgtipwqvkuktmc.png" alt="Attempt 1" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first instinct was the obvious one. S3 Files exposes a mount target with a private IP in your VPC. I put an internet-facing Network Load Balancer in front of it (TCP 2049), pointed my Mac at the NLB, and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; nfs &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;vers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 nlb-dns.amazonaws.com:/ /mnt/s3files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The screen went black. Hard reboot. I tried again with different NFS options. Black screen. Reboot. I tried &lt;code&gt;vers=4.0&lt;/code&gt; explicitly. Black screen. Reboot.&lt;/p&gt;

&lt;p&gt;Five kernel panics in total. macOS NFSv4 bugs are &lt;a href="https://discussions.apple.com/thread/255788888" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt; — the client chokes on protocol features it doesn't understand. When S3 Files responds with NFSv4.2 capabilities, the macOS NFS client doesn't gracefully degrade. It crashes the kernel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: macOS NFSv4 is not just old — it's actively dangerous when pointed at a v4.2 server.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2: Raw &lt;code&gt;mount -t nfs4&lt;/code&gt; via NLB → ❌ "access denied"
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetkn7fn6gcgpgdok8vkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetkn7fn6gcgpgdok8vkw.png" alt="Attempt 2" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, so macOS is out. I spun up a Docker container running Amazon Linux (which has a proper NFSv4.2 client) and tried a raw NFS mount from inside the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; nfs4 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;nfsvers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.2 nlb-dns.amazonaws.com:/ /mnt/s3files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Access denied."&lt;/p&gt;

&lt;p&gt;This is where I started reading the &lt;code&gt;efs-utils&lt;/code&gt; source code. S3 Files isn't a standard NFS server you can just connect to. Before any NFS traffic flows, the client must authenticate via a custom protocol called EFS RPC Bind — essentially proving "I have valid AWS credentials and I'm allowed to mount this filesystem." The &lt;code&gt;efs-proxy&lt;/code&gt; binary handles this. A raw &lt;code&gt;mount -t nfs4&lt;/code&gt; skips the entire auth layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: You can't just NFS-mount S3 Files. The auth isn't optional — it's the only way in.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 3: efs-proxy Without TLS → ❌ "access denied"
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg678c2685ehlogs05owf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg678c2685ehlogs05owf.png" alt="Attempt 3" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I installed &lt;code&gt;amazon-efs-utils&lt;/code&gt; in the container and tried &lt;code&gt;mount -t s3files&lt;/code&gt;. The &lt;code&gt;efs-proxy&lt;/code&gt; binary started up, but I hadn't configured TLS properly (Docker isn't EC2 — there's no instance metadata service, no AZ info, no automatic certificate provisioning).&lt;/p&gt;

&lt;p&gt;"Access denied." Again.&lt;/p&gt;

&lt;p&gt;Digging into the &lt;code&gt;efs-utils&lt;/code&gt; config, I found that &lt;code&gt;efs-proxy&lt;/code&gt; wraps the TCP connection to port 2049 in TLS 1.2, then performs an RPC Bind — a custom handshake where the client proves it has valid AWS credentials. Think of it as mTLS with IAM instead of certificates. Without TLS, the mount target drops the connection before auth even begins.&lt;/p&gt;

&lt;p&gt;I patched the config file (&lt;code&gt;/etc/amazon/efs/s3files-utils.conf&lt;/code&gt;) to remove the &lt;code&gt;{az_id}&lt;/code&gt; placeholder from the DNS format (no AZ metadata in Docker) and set the region via environment variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: S3 Files enforces TLS on every single connection. No TLS, no mount. Period.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 4: The IPv6 Detour → ✅ First Success (But Wrong Conclusion)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczeaf39c71hazgabcr4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczeaf39c71hazgabcr4h.png" alt="Attempt 4" width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point I was convinced the NLB was the problem. Something about how it proxied TCP was breaking S3 Files at the NFS protocol level. So I built a workaround: bypass the NLB entirely.&lt;/p&gt;

&lt;p&gt;The mount target ENI had an IPv6 address (assigned by the subnet's IPv6 CIDR). My Mac has IPv6 connectivity. Docker Desktop doesn't — but I could bridge the gap with a Python TCP proxy on my Mac that accepts IPv4 from Docker and forwards to the mount target over IPv6.&lt;/p&gt;

&lt;p&gt;This required opening the mount target's security group directly to my public IPv6 address on port 2049. Not great — exposing a mount target to the internet is exactly the kind of thing Security Hub flags. But for debugging, I went with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Docker → Mac TCP bridge (IPv4:2049) → IPv6 → Mount Target (SG opened for my IPv6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the container, I used &lt;code&gt;mount -t s3files&lt;/code&gt; with &lt;code&gt;mounttargetip&lt;/code&gt; pointing at the Mac's Docker gateway. And it worked. Files appeared. Read/write confirmed. S3 sync verified. First success after hours of debugging.&lt;/p&gt;

&lt;p&gt;But &lt;em&gt;why&lt;/em&gt; did it work when the NLB path didn't? I assumed it was because I'd eliminated the NLB. Wrong.&lt;/p&gt;

&lt;p&gt;The real reason: &lt;code&gt;mount -t s3files&lt;/code&gt; automatically enables TLS. My earlier attempts used manual &lt;code&gt;efs-proxy&lt;/code&gt; commands &lt;em&gt;without&lt;/em&gt; TLS. The official mount helper adds it by default — S3 Files won't work without it.&lt;/p&gt;

&lt;p&gt;Retried the NLB with &lt;code&gt;mount -t s3files&lt;/code&gt; instead of manual &lt;code&gt;efs-proxy&lt;/code&gt;. Worked perfectly. &lt;strong&gt;TLS was the missing piece all along.&lt;/strong&gt; The NLB was fine — it's Layer 4, it just passes TCP bytes through, TLS and all.&lt;/p&gt;

&lt;p&gt;I deleted the TCP bridge, removed the IPv6 SG rule, and moved on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: when something works through path A but not path B, the difference might not be the path — it might be what path A does automatically that you forgot to do on path B.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 5: efs-proxy ReadBypass → ❌ Proxy Crash Loop
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnammwybir6po34xrtgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnammwybir6po34xrtgu.png" alt="Attempt 5" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the NLB working via &lt;code&gt;mount -t s3files&lt;/code&gt;, I had one more problem. During my earlier manual &lt;code&gt;efs-proxy&lt;/code&gt; debugging (before discovering the TLS fix), I'd hit a persistent crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR efs_proxy::nfs::nfs_reader Error handling parsing error SendError { .. }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy would connect, authenticate (BindResponse::READY), then crash the moment NFS traffic flowed. Restart. Crash. Restart. Hundreds of incarnations per second.&lt;/p&gt;

&lt;p&gt;After reading the &lt;code&gt;efs-proxy&lt;/code&gt; source and the &lt;code&gt;mount.s3files&lt;/code&gt; Python wrapper, I found the culprit: the &lt;strong&gt;ReadBypass module&lt;/strong&gt;. Remember how S3 Files serves large files directly from S3's throughput layer? ReadBypass is the &lt;code&gt;efs-proxy&lt;/code&gt; implementation of that — it intercepts NFS read requests and serves them directly from S3, bypassing the NFS data path. This is designed for EC2 instances with direct VPC access to S3. In our setup — Docker container, patched efs-utils config, traffic routed through an NLB — the parser chokes on certain response formats and panics. It's not necessarily a bug in ReadBypass itself; it's that we're running &lt;code&gt;efs-proxy&lt;/code&gt; far outside its intended environment.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;efs-proxy&lt;/code&gt; binary accepts a &lt;code&gt;--no-direct-s3-read&lt;/code&gt; flag (I found this by running &lt;code&gt;efs-proxy --help&lt;/code&gt; after the &lt;code&gt;--no-read-bypass&lt;/code&gt; flag I guessed didn't exist). The &lt;code&gt;mount -t s3files&lt;/code&gt; equivalent is the &lt;code&gt;nodirects3read&lt;/code&gt; mount option.&lt;/p&gt;

&lt;p&gt;With ReadBypass disabled, the proxy forwarded NFS traffic cleanly. No crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: &lt;code&gt;efs-proxy&lt;/code&gt; ReadBypass doesn't work in our non-standard Docker + NLB setup. Use &lt;code&gt;nodirects3read&lt;/code&gt; to disable it. On a normal EC2 instance, it likely works fine.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 6: The Full Stack → ✅ It Works
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4lhgola3t1hnrt8h1v3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4lhgola3t1hnrt8h1v3.png" alt="Attempt 6" width="800" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The winning combination:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; (Amazon Linux) — provides NFSv4.2 kernel support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;efs-proxy&lt;/strong&gt; — handles TLS + IAM authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NLB&lt;/strong&gt; — bridges Docker Desktop to the VPC mount target&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nodirects3read&lt;/code&gt;&lt;/strong&gt; — avoids the ReadBypass crash&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebDAV&lt;/strong&gt; — re-exports the NFS mount to macOS as a native folder&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Wait — WebDAV? Why not just use the Docker mount directly?&lt;/p&gt;

&lt;p&gt;Because Docker Desktop runs in a Linux VM. The NFS mount lives inside that VM. To access it from macOS, you need to re-export it over a protocol that macOS can mount natively. The two candidates: SMB (Samba) and WebDAV.&lt;/p&gt;

&lt;p&gt;I benchmarked both. The results were... not close.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benchmark: WebDAV Destroys SMB on macOS
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Docker (NFS direct)&lt;/th&gt;
&lt;th&gt;Mac (WebDAV)&lt;/th&gt;
&lt;th&gt;Mac (SMB)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List directory&lt;/td&gt;
&lt;td&gt;0.09s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.08s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read small file&lt;/td&gt;
&lt;td&gt;0.13s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.05s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.49s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write + read back&lt;/td&gt;
&lt;td&gt;0.27s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.53s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.7s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;th&gt;Docker (NFS)&lt;/th&gt;
&lt;th&gt;WebDAV&lt;/th&gt;
&lt;th&gt;SMB&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10 MB write&lt;/td&gt;
&lt;td&gt;1.2s&lt;/td&gt;
&lt;td&gt;1.4s&lt;/td&gt;
&lt;td&gt;11.0s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 MB read&lt;/td&gt;
&lt;td&gt;0.10s&lt;/td&gt;
&lt;td&gt;0.03s&lt;/td&gt;
&lt;td&gt;0.42s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100 MB write&lt;/td&gt;
&lt;td&gt;6.8s&lt;/td&gt;
&lt;td&gt;9.3s&lt;/td&gt;
&lt;td&gt;87.0s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write throughput&lt;/td&gt;
&lt;td&gt;~15 MB/s&lt;/td&gt;
&lt;td&gt;~11 MB/s&lt;/td&gt;
&lt;td&gt;~1.1 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read throughput&lt;/td&gt;
&lt;td&gt;~830 MB/s&lt;/td&gt;
&lt;td&gt;~400 MB/s&lt;/td&gt;
&lt;td&gt;~24 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;WebDAV is &lt;strong&gt;10–54x faster&lt;/strong&gt; than SMB on macOS. Apple's SMB client is notoriously slow — it adds packet signing, metadata prefetching, and delayed TCP acknowledgments to every operation. A simple &lt;code&gt;ls&lt;/code&gt; triggers dozens of round-trips. WebDAV is just HTTP requests — one request, one response, done.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://github.com/mar10/wsgidav" rel="noopener noreferrer"&gt;WsgiDAV&lt;/a&gt; as the WebDAV server inside the container. It re-exports the NFS mount at &lt;code&gt;/mnt/s3files&lt;/code&gt; over HTTP on port 8080. macOS mounts it natively via &lt;code&gt;mount_webdav&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Region Matters: ca-central-1 vs us-east-2
&lt;/h2&gt;

&lt;p&gt;Since the latency floor is internet RTT, I deployed the same CDK stack to two regions and benchmarked from my Mac in Canada:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation (Docker NFS)&lt;/th&gt;
&lt;th&gt;us-east-2&lt;/th&gt;
&lt;th&gt;ca-central-1&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List directory&lt;/td&gt;
&lt;td&gt;0.09s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.08s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read small file&lt;/td&gt;
&lt;td&gt;0.13s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.06s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2x faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write + read back&lt;/td&gt;
&lt;td&gt;0.27s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.16s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40% faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10MB write&lt;/td&gt;
&lt;td&gt;1.2s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.0s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10MB read&lt;/td&gt;
&lt;td&gt;0.10s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.06s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;40% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CDK stack is region-agnostic — just change &lt;code&gt;-c region=ca-central-1&lt;/code&gt;. Pick the region closest to you. For me in Canada, ca-central-1 shaves ~40% off interactive operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3by2zccaruza50x2h3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3by2zccaruza50x2h3.png" alt="S3 Files Console" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqcxicq6vy6rfpxq9z4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqcxicq6vy6rfpxq9z4n.png" alt="macOS Finder" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfp9t1bdcdkafjuequ1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfp9t1bdcdkafjuequ1a.png" alt="Architecture" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your Mac talks WebDAV to a Docker container. The container talks authenticated, encrypted NFSv4.2 to S3 Files through an NLB. The NLB is Layer 4 — it just forwards TCP bytes without inspecting or modifying the TLS payload. S3 Files syncs bidirectionally with your S3 bucket. From your Mac's perspective, it's just a folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer Experience: Two Commands
&lt;/h2&gt;

&lt;p&gt;I wrapped everything in a CDK stack and a shell script. The entire setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Deploy infrastructure (VPC, bucket, IAM role, S3 Files, NLB)&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx cdk deploy &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca-central-1

&lt;span class="c"&gt;# 2. Mount&lt;/span&gt;
./docker/docker-mount.sh up &amp;lt;NLB_DNS_from_CDK_output&amp;gt;

&lt;span class="c"&gt;# 3. Use it&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; /tmp/s3files/
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello world"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/s3files/test.txt
open /tmp/s3files  &lt;span class="c"&gt;# opens in Finder&lt;/span&gt;
code /tmp/s3files  &lt;span class="c"&gt;# opens in VS Code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;code&gt;docker-mount.sh up&lt;/code&gt; builds the container, starts &lt;code&gt;efs-proxy&lt;/code&gt;, mounts S3 Files via NFS, starts the WebDAV server, and mounts WebDAV at &lt;code&gt;/tmp/s3files&lt;/code&gt;. One command. To tear down: &lt;code&gt;docker-mount.sh down&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The CDK stack provisions everything: VPC with public subnet, S3 bucket (versioning enabled — required by S3 Files), IAM role with the &lt;code&gt;elasticfilesystem.amazonaws.com&lt;/code&gt; trust policy, the S3 Files filesystem and mount target, an NLB forwarding TCP 2049, and security groups locking it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Backstory: Mountpoint for S3 and the iPhone Backup That Almost Worked
&lt;/h2&gt;

&lt;p&gt;This isn't my &lt;a href="https://aws.plainenglish.io/mounting-amazon-s3-buckets-on-windows-52b5f1434cd7" rel="noopener noreferrer"&gt;first attempt&lt;/a&gt; at mounting S3 locally. Last year, I experimented with &lt;a href="https://github.com/awslabs/mountpoint-s3" rel="noopener noreferrer"&gt;Mountpoint for Amazon S3&lt;/a&gt; on Windows via WSL2. Mountpoint is a FUSE-based client that presents S3 as a local filesystem — but it's optimized for read-heavy workloads. Writes are limited: you can create new files, but you can't modify existing ones in place.&lt;/p&gt;

&lt;p&gt;I had a wild idea: back up my iPhone to S3 via iTunes. I mounted an S3 bucket using Mountpoint in WSL2, pointed iTunes at it, and kicked off a backup. The initial full backup actually worked — iTunes wrote all the files sequentially, which is exactly what Mountpoint handles well.&lt;/p&gt;

&lt;p&gt;Then I tried an incremental backup. iTunes needs to read existing backup files, compare them, and overwrite changed ones. Mountpoint doesn't support overwrites. The backup failed.&lt;/p&gt;

&lt;p&gt;S3 Files changes this equation entirely. Full read/write. In-place modifications. Bidirectional sync. The filesystem semantics that iTunes (and every other desktop app) expects. I haven't re-tested the iPhone backup scenario yet with S3 Files, but the technical blockers that stopped Mountpoint are gone. This could finally be the path to backing up an iPhone directly to S3 with full incremental support.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: Use Cases I'm Excited About
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shared IDE workspace.&lt;/strong&gt; Mount the same S3 bucket from multiple machines. Edit files in VS Code on your Mac, pick up where you left off on your Linux workstation. S3 is the source of truth. No git push/pull dance for work-in-progress files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic AI shared state.&lt;/strong&gt; This is the one that keeps me up at night. AI agents — coding assistants like Kiro, autonomous agents like OpenClaw — increasingly work with files: markdown docs, config files, memory stores, tool outputs. Mount an S3-backed filesystem as the agent's workspace. Multiple agents can read and write to the same shared state. The data lives in S3, durable and accessible from anywhere. It's a shared brain for your agent fleet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform development.&lt;/strong&gt; Same S3 bucket, three platforms: macOS (via Docker + WebDAV), Windows (via WSL2 — native NFSv4.2, no Docker needed), Linux (native &lt;code&gt;mount -t s3files&lt;/code&gt;). One source of truth, zero file sync tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on WSL2
&lt;/h2&gt;

&lt;p&gt;If you're on Windows, you might not need Docker at all. WSL2 runs a real Linux kernel (5.15+) with full NFSv4.2 support. You can install &lt;code&gt;amazon-efs-utils&lt;/code&gt; directly in WSL2 and mount S3 Files natively — no WebDAV re-export, no container overhead. The mount appears as a Linux path accessible from Windows Explorer via &lt;code&gt;\\wsl$\&lt;/code&gt;. You'd still need the NLB (or a VPN) for connectivity, but the protocol stack is native. I haven't tested this yet, but the kernel capabilities are all there.&lt;/p&gt;

&lt;h2&gt;
  
  
  S3 Files vs. Mountpoint for Amazon S3
&lt;/h2&gt;

&lt;p&gt;For anyone wondering how these two compare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;S3 Files&lt;/th&gt;
&lt;th&gt;Mountpoint for S3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;NFS (NFSv4.2)&lt;/td&gt;
&lt;td&gt;FUSE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read/Write&lt;/td&gt;
&lt;td&gt;Full read/write&lt;/td&gt;
&lt;td&gt;Read-heavy (limited writes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Sub-millisecond&lt;/td&gt;
&lt;td&gt;Milliseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync&lt;/td&gt;
&lt;td&gt;Bidirectional (S3 ↔ filesystem)&lt;/td&gt;
&lt;td&gt;One-way (S3 → filesystem)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires&lt;/td&gt;
&lt;td&gt;Mount target in VPC&lt;/td&gt;
&lt;td&gt;Just IAM credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;Linux only (EC2, ECS, EKS, Lambda)&lt;/td&gt;
&lt;td&gt;Linux, macOS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;S3 Files is a managed NFS filesystem with S3 as the durable backend. Mountpoint is a lightweight FUSE client for reading large datasets from S3. Different tools for different jobs. S3 Files gives you the full filesystem semantics that applications like databases, IDEs, and backup tools expect. Mountpoint gives you fast, cheap reads for data pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security: What's Safe and What's Not
&lt;/h2&gt;

&lt;p&gt;The PoC uses an internet-facing NLB so Docker Desktop can reach the mount target. This sounds scary, but the actual risk is mitigated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 Files enforces TLS encryption and IAM authentication on every connection — you can't mount without valid AWS credentials&lt;/li&gt;
&lt;li&gt;The NLB security group only allows inbound TCP 2049&lt;/li&gt;
&lt;li&gt;The mount target security group only accepts traffic from the NLB security group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, &lt;strong&gt;for production use&lt;/strong&gt;, replace the public NLB with &lt;a href="https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/what-is.html" rel="noopener noreferrer"&gt;AWS Client VPN&lt;/a&gt;. AWS documents this exact pattern for &lt;a href="https://docs.aws.amazon.com/efs/latest/ug/efs-onpremises.html" rel="noopener noreferrer"&gt;accessing EFS from on-premises networks&lt;/a&gt;, and it applies equally to S3 Files. VPN eliminates the internet-facing endpoint entirely. Also use private subnets with a &lt;a href="https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html" rel="noopener noreferrer"&gt;Gateway endpoint for S3&lt;/a&gt; — it's free and routes S3 traffic through the AWS network, bypassing NAT Gateway costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Failure Table
&lt;/h2&gt;

&lt;p&gt;Because every good debugging story deserves a summary of the wreckage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Root Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native macOS NFS mount&lt;/td&gt;
&lt;td&gt;💀 Kernel panic (5x)&lt;/td&gt;
&lt;td&gt;macOS NFSv4.0 can't handle v4.2 responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raw &lt;code&gt;mount -t nfs4&lt;/code&gt; (no efs-proxy)&lt;/td&gt;
&lt;td&gt;❌ "access denied"&lt;/td&gt;
&lt;td&gt;Missing EFS RPC Bind authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;efs-proxy without TLS&lt;/td&gt;
&lt;td&gt;❌ "access denied"&lt;/td&gt;
&lt;td&gt;S3 Files requires TLS on all connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;efs-proxy with ReadBypass&lt;/td&gt;
&lt;td&gt;❌ Proxy crash loop&lt;/td&gt;
&lt;td&gt;ReadBypass incompatible with Docker + NLB setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker + efs-proxy + TLS + NLB + &lt;code&gt;nodirects3read&lt;/code&gt; + WebDAV&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Works&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;All requirements met&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The entire project is open source (MIT): &lt;strong&gt;&lt;a href="https://github.com/awsdataarchitect/s3files-mount" rel="noopener noreferrer"&gt;github.com/awsdataarchitect/s3files-mount&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two commands to go from zero to a native Mac folder backed by S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx cdk deploy &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca-central-1
./docker/docker-mount.sh up &amp;lt;NLB_DNS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try it, break it, improve it, or find new use cases — I'd love to hear about it. Open an issue, submit a PR, or find me on LinkedIn.&lt;/p&gt;

&lt;p&gt;S3 has never been a filesystem. But as of this week, your S3 data can live in one — even on your Mac.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>showdev</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The AWS Dev Setup Nobody Told You About. Claude Code, Kiro Pro, and Agent Plugins.</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Sun, 05 Apr 2026 02:45:49 +0000</pubDate>
      <link>https://dev.to/aws-heroes/the-aws-dev-setup-nobody-told-you-about-claude-code-kiro-pro-and-agent-plugins-1c3p</link>
      <guid>https://dev.to/aws-heroes/the-aws-dev-setup-nobody-told-you-about-claude-code-kiro-pro-and-agent-plugins-1c3p</guid>
      <description>&lt;h2&gt;
  
  
  Agent Plugins for AWS
&lt;/h2&gt;

&lt;p&gt;AWS recently released &lt;a href="https://github.com/awslabs/agent-plugins" rel="noopener noreferrer"&gt;Agent Plugins for AWS&lt;/a&gt;, a set of structured skill packs for Claude Code covering serverless, deployment, SageMaker, and more. I wanted to test them. I already have a Kiro Pro subscription, so I used &lt;a href="https://github.com/jwadow/kiro-gateway" rel="noopener noreferrer"&gt;kiro-gateway&lt;/a&gt; to route Claude Code through it. No extra API subscription needed. Here's how that worked, and what broke along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3w79sz0047dw2x3viz2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3w79sz0047dw2x3viz2q.png" alt="setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude Code supports a &lt;code&gt;ANTHROPIC_BASE_URL&lt;/code&gt; environment variable. Point it at a local kiro-gateway instance and Claude Code thinks it's talking to Anthropic's API. The requests route through your Kiro Pro subscription instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install Claude Code
&lt;/h3&gt;

&lt;p&gt;Requires Claude Code version 2.1.29 or later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Clone and set up kiro-gateway
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 https://github.com/jwadow/kiro-gateway ~/kiro-gateway
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/kiro-gateway
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
.venv/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Configure kiro-gateway
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;~/kiro-gateway/.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PROXY_API_KEY="kiro-local-proxy-key"
KIRO_CLI_DB_FILE="/Users/&amp;lt;YOUR_USER&amp;gt;/Library/Application Support/kiro-cli/data.sqlite3"
SERVER_HOST="127.0.0.1"
SERVER_PORT="9000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;KIRO_CLI_DB_FILE&lt;/code&gt; path points to your kiro-cli's auth database. On macOS it's under &lt;code&gt;~/Library/Application Support/kiro-cli/data.sqlite3&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Start kiro-gateway
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/kiro-gateway/.venv/bin/python ~/kiro-gateway/main.py &lt;span class="nt"&gt;--port&lt;/span&gt; 9000 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Point Claude Code at it
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;~/.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:9000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kiro-local-proxy-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_MODEL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4-6-20250929"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Run Claude Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first run it asks "Do you want to use this API key?" Select Yes. That's the gateway proxy key. Anthropic never sees it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7. Install Agent Plugins
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/awslabs/agent-plugins" rel="noopener noreferrer"&gt;AWS Agent Plugins&lt;/a&gt; package four types of artifacts into a single installable unit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt;: structured workflows that guide Claude through complex tasks step by step. This is the core.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP servers&lt;/strong&gt;: connections to live data, pricing APIs, documentation, and IaC validators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt;: automation that runs on developer actions, like validating a SAM template after every edit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;References&lt;/strong&gt;: documentation and config defaults that skills consult during execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install them from inside Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add awslabs/agent-plugins
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;deploy-on-aws@agent-plugins-for-aws
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;aws-serverless@agent-plugins-for-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Code after installing. Seven plugins are available in the marketplace: &lt;code&gt;deploy-on-aws&lt;/code&gt;, &lt;code&gt;aws-serverless&lt;/code&gt;, &lt;code&gt;aws-amplify&lt;/code&gt;, &lt;code&gt;databases-on-aws&lt;/code&gt;, &lt;code&gt;amazon-location-service&lt;/code&gt;, &lt;code&gt;migration-to-aws&lt;/code&gt;, and &lt;code&gt;sagemaker-ai&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What each plugin does
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aws-serverless&lt;/code&gt; ships three skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;aws-lambda&lt;/code&gt;: Lambda functions, event sources, API Gateway, EventBridge, and Step Functions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws-serverless-deployment&lt;/code&gt;: SAM and CDK deployment workflows&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws-lambda-durable-functions&lt;/code&gt;: workflow orchestration, saga patterns, and human-in-the-loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you ask Claude to build a serverless API, the relevant skill drives the process. The &lt;code&gt;aws-serverless-mcp&lt;/code&gt; server provides live data underneath.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;deploy-on-aws&lt;/code&gt; ships a single &lt;code&gt;deploy&lt;/code&gt; skill with a five-step workflow: Analyze, Recommend, Estimate, Generate, Deploy. Three MCP servers back it: &lt;code&gt;awsknowledge&lt;/code&gt; for architecture decisions, &lt;code&gt;awspricing&lt;/code&gt; for live cost data, and &lt;code&gt;aws-iac-mcp&lt;/code&gt; for CDK and CloudFormation validation. The Generate step produces CDK or CloudFormation code with security defaults applied. The Deploy step executes with your confirmation.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;aws-serverless&lt;/code&gt; plugin also ships a hook that runs &lt;code&gt;sam validate&lt;/code&gt; automatically after every edit to &lt;code&gt;template.yaml&lt;/code&gt;. You don't configure it. It fires on save and surfaces errors immediately.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sagemaker-ai&lt;/code&gt; is the newest addition. It ships 12 skills covering the full model customization lifecycle: use case definition, dataset evaluation, fine-tuning, model evaluation, and deployment on Amazon SageMaker AI. It also includes skills for managing SageMaker HyperPod clusters, running remote diagnostics via AWS Systems Manager, and generating issue reports. Install it the same way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin &lt;span class="nb"&gt;install &lt;/span&gt;sagemaker-ai@agent-plugins-for-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trying it out. Cost estimation
&lt;/h3&gt;

&lt;p&gt;Type this prompt exactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy a serverless TODO API with DynamoDB. Estimate the monthly cost at 10,000 requests/day.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctj676ukb2gv0qlbovrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctj676ukb2gv0qlbovrf.png" alt="agent-plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;deploy-on-aws&lt;/code&gt; skill runs its Analyze and Estimate steps. It calls &lt;code&gt;get_pricing&lt;/code&gt; three times against the AWS Price List API: once each for Lambda, API Gateway, and DynamoDB. The cost table uses live numbers pulled at query time.&lt;/p&gt;

&lt;p&gt;At 10,000 requests/day (300,000/month), the breakdown looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lambda requests&lt;/td&gt;
&lt;td&gt;300K (free tier: 1M)&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda duration&lt;/td&gt;
&lt;td&gt;7,680 GB-sec (free tier: 400K)&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Gateway (HTTP)&lt;/td&gt;
&lt;td&gt;300K @ $1.00/million&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB reads&lt;/td&gt;
&lt;td&gt;180K RRUs @ $0.125/million&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB writes&lt;/td&gt;
&lt;td&gt;120K WRUs @ $0.625/million&lt;/td&gt;
&lt;td&gt;$0.08&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB storage&lt;/td&gt;
&lt;td&gt;~1 MB&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total: ~$0.40/month&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the screenshot moment. The skill called real AWS pricing APIs to produce that table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyfqrzww3hfnqb1c2oj1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyfqrzww3hfnqb1c2oj1.png" alt="agent-plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Trying it out. Full plugin-driven deployment
&lt;/h3&gt;

&lt;p&gt;The cost estimation above is the Estimate step. If you continue, the skill runs Generate next. That produces CDK or CloudFormation code with security defaults applied. Then Deploy runs an IaC security scan and asks for your confirmation before executing.&lt;/p&gt;

&lt;p&gt;For the SAM path, the &lt;code&gt;aws-serverless&lt;/code&gt; plugin takes over. Ask Claude to drive it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Use SAM to deploy a serverless TODO API with DynamoDB to us-east-1.
Build and deploy it using the SAM tools.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude calls &lt;code&gt;sam_init&lt;/code&gt; to scaffold the project, &lt;code&gt;sam_build&lt;/code&gt; to compile it, and &lt;code&gt;sam_deploy&lt;/code&gt; to push it to AWS. The &lt;code&gt;aws-serverless-deployment&lt;/code&gt; skill guides each step.&lt;/p&gt;

&lt;p&gt;Both paths use the plugins end-to-end. The difference is which skill drives the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting kiro-gateway:
&lt;/h2&gt;

&lt;p&gt;kiro-gateway is an open-source project with active development. It works well for personal testing and experimentation, but expect some rough edges. Responses are slightly slower than direct Anthropic API calls because requests route through an extra local hop. Good enough for exploration.&lt;/p&gt;

&lt;p&gt;Here are the two issues I hit.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Long tool names trigger a 400 error
&lt;/h3&gt;

&lt;p&gt;Once Agent Plugins were installed, I immediately got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;400 Improperly formed request
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MCP servers generate verbose tool names like &lt;code&gt;mcp__GitHub__check_if_a_repository_is_starred_by_the_authenticated_user&lt;/code&gt; (71 characters). The Kiro API has a hard 64-character limit. The original kiro-gateway code threw an error on any name over that limit, which broke every MCP server with descriptive tool names.&lt;/p&gt;

&lt;p&gt;The fix is a patch to kiro-gateway that transparently shortens names before sending to Kiro and restores the originals in responses. Claude Code and MCP servers see the full names. Kiro sees names that fit its limit. I built this locally with Claude Code's help. It's not yet submitted upstream, so if you hit the same error, the patch is something you'd apply yourself for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. aws-iac-mcp fails to build on Apple Silicon
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;aws-iac-mcp&lt;/code&gt; server failed to start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the `x86_64-apple-darwin` target may not be installed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It depends on &lt;code&gt;guardpycfn&lt;/code&gt;, a Rust-based Python package. On Apple Silicon, the build tool tried to cross-compile for x86_64 but the Rust target wasn't installed. One command fixes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rustup target add x86_64-apple-darwin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Code after running it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage (again after fix)
&lt;/h2&gt;

&lt;p&gt;Start the gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/kiro-gateway/.venv/bin/python ~/kiro-gateway/main.py &lt;span class="nt"&gt;--port&lt;/span&gt; 9000 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check gateway health:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:9000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;$0 extra. Your existing Kiro Pro subscription just works for this local experience. Claude Code uses the standard Anthropic API protocol. kiro-gateway translates it to Kiro. &lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/jwadow" rel="noopener noreferrer"&gt;@jwadow&lt;/a&gt; for &lt;a href="https://github.com/jwadow/kiro-gateway" rel="noopener noreferrer"&gt;kiro-gateway&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awslabs" rel="noopener noreferrer"&gt;awslabs&lt;/a&gt; for &lt;a href="https://github.com/awslabs/agent-plugins" rel="noopener noreferrer"&gt;Agent Plugins for AWS&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>I Built a Real-Time Voice AI Confession Guide for 1.39 Billion Catholics. Every Bug Was Invisible.</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Thu, 26 Mar 2026 15:44:40 +0000</pubDate>
      <link>https://dev.to/aws-heroes/i-built-a-real-time-voice-ai-confession-guide-for-139-billion-catholics-every-bug-was-invisible-2j9o</link>
      <guid>https://dev.to/aws-heroes/i-built-a-real-time-voice-ai-confession-guide-for-139-billion-catholics-every-bug-was-invisible-2j9o</guid>
      <description>&lt;h2&gt;
  
  
  The Gap
&lt;/h2&gt;

&lt;p&gt;75% of U.S. Catholics say they never go to confession or go less than once a year. Only 2% confess monthly. Those numbers come from Pew Research and CARA at Georgetown, and they've been trending in one direction for decades.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://apps.apple.com/app/mass-time/id1438037116" rel="noopener noreferrer"&gt;Mass Time&lt;/a&gt;, an iOS app with 280,000+ churches indexed, 60 prayers, and daily readings. I've watched the confession problem from the data side for years. People want to go. They feel anxious. They don't know what to say. They haven't been in so long that the guilt of &lt;em&gt;not going&lt;/em&gt; becomes the reason they &lt;em&gt;keep not going&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In 2025, the late Pope Francis declared a Jubilee Year and specifically called for increased access to the Sacrament of Reconciliation. The demand is real. The infrastructure isn't.&lt;/p&gt;

&lt;p&gt;So I built an AI confession guide. No AI will ever replace a priest. Only a priest can grant absolution. This is a preparation tool. You talk to your phone. It talks back. Seven languages. No keyboard. Just a conversation that helps you organize your thoughts before you walk into that booth.&lt;/p&gt;

&lt;p&gt;It uses Amazon Nova 2 Sonic, a bi-directional speech-to-speech model, running on Amazon Bedrock AgentCore Runtime. The bugs I hit building it were the worst kind: silent, invisible, and plausible enough to make you doubt everything except the actual problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;Simple on paper. Brutal in practice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c7glzebjelnxr1pb0wm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c7glzebjelnxr1pb0wm.png" alt="masstime" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nova 2 Sonic handles the heavy lifting. It takes raw audio in, processes speech bidirectionally, and sends audio back. No separate STT or TTS pipeline. One model, both directions, real-time.&lt;/p&gt;

&lt;p&gt;The server is a Python 3.13 container on AgentCore Runtime. The client is native Swift with AVAudioEngine. No web views, no React Native. Seven polyglot voices: English (Matthew), French (Florian), Spanish (Carlos), Italian (Lorenzo), German (Lennart), Portuguese (Leo), and Hindi (Arjun). Users can switch languages mid-conversation and the AI follows.&lt;/p&gt;

&lt;p&gt;Region constraint worth knowing: Nova 2 Sonic is only available in us-east-1, us-west-2, and ap-northeast-1. I learned the us-east-2 limitation the hard way when my first deployment returned a model-not-found error.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bug That Almost Shipped
&lt;/h2&gt;

&lt;p&gt;Nova 2 Sonic never responded to speech. I tried the Strands Agents SDK. Raw API calls. Different prompts. Different voices. Nothing.&lt;/p&gt;

&lt;p&gt;The audio RMS values from the mic looked normal. Waveforms had energy. Everything &lt;em&gt;seemed&lt;/em&gt; fine.&lt;/p&gt;

&lt;p&gt;One line of Swift was wrong.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// WRONG: reads pointer-to-pointer memory (garbage audio)&lt;/span&gt;
&lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outBuf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int16ChannelData&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// CORRECT: reads actual audio samples&lt;/span&gt;
&lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outBuf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int16ChannelData&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;int16ChannelData&lt;/code&gt; is &lt;code&gt;UnsafePointer&amp;lt;UnsafeMutablePointer&amp;lt;Int16&amp;gt;&amp;gt;&lt;/code&gt;. A pointer to an array of channel pointers. Without &lt;code&gt;[0]&lt;/code&gt;, you're reading the pointer addresses themselves as audio samples.&lt;/p&gt;

&lt;p&gt;The RMS looked plausible because memory addresses happen to have high values. The model received garbage that &lt;em&gt;looked like audio&lt;/em&gt; in every metric except the one that mattered: it wasn't audio.&lt;/p&gt;

&lt;p&gt;I confirmed it by injecting known-good PCM on the server side. Model responded perfectly. Fixed the iOS code. Real mic audio worked.&lt;/p&gt;

&lt;p&gt;One missing array subscript. Hours of debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two More Invisible Bugs
&lt;/h2&gt;

&lt;p&gt;The app crashed on every AI response with &lt;code&gt;_outputFormat.channelCount == buffer.format.channelCount&lt;/code&gt;. AVAudioPlayerNode was connected with the mixer's stereo format but I was scheduling mono buffers. Nova 2 Sonic outputs 24kHz mono PCM. The mixer expects stereo by default.&lt;/p&gt;

&lt;p&gt;Fix: connect the player node with an explicit mono format matching the model's output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;playFmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AVAudioFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;commonFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pcmFormatInt16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;interleaved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;audioEngine&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerNode&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audioEngine&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;mainMixerNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;playFmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key detail that isn't obvious from the docs: Nova 2 Sonic input is 16kHz 16-bit mono PCM, but output is 24kHz 16-bit mono PCM. Different sample rates in each direction.&lt;/p&gt;

&lt;p&gt;Then the mic auto-unmute timer never fired. After the AI spoke, the mic stayed muted permanently. No error. No warning. Just silence.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Timer.scheduledTimer&lt;/code&gt; was called from the WebSocket callback thread. That thread has no RunLoop. The timer was created, registered to nothing, and quietly ignored. This is one of those iOS gotchas that experienced developers know and everyone else discovers at 2 AM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cognito Session Policy Trap
&lt;/h2&gt;

&lt;p&gt;This one is invisible and will waste your entire day.&lt;/p&gt;

&lt;p&gt;Cognito Identity Pools have two auth flows: Enhanced (default) and Basic (classic). Every tutorial uses Enhanced. It works fine for S3, DynamoDB, Lambda.&lt;/p&gt;

&lt;p&gt;It does not work for Amazon Bedrock (currently).&lt;/p&gt;

&lt;p&gt;Enhanced flow calls &lt;code&gt;getCredentialsForIdentity&lt;/code&gt;, which injects a restrictive session policy that limits credentials to a subset of AWS services. Bedrock is not in that subset. Your IAM role policy can be perfect. You'll still get &lt;code&gt;AccessDeniedException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The error message says "no session policy allows" but doesn't tell you Cognito is injecting it. You can't see this policy in IAM, CloudTrail, or the Cognito console. It's completely invisible.&lt;/p&gt;

&lt;p&gt;Fix: one boolean in CDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;identityPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cognito&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnIdentityPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pool&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;allowUnauthenticatedIdentities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowClassicFlow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// This is the entire fix&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the client side, the classic flow requires three calls instead of one: &lt;code&gt;getId&lt;/code&gt; → &lt;code&gt;getOpenIdToken&lt;/code&gt; → STS &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt;. The STS call is an unsigned HTTP POST, so you don't even need the STS SDK.&lt;/p&gt;

&lt;p&gt;One boolean. Hours of debugging. Not documented clearly anywhere. This affects all Bedrock actions, not just Nova 2 Sonic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frugal Architecture: 60 Concurrent Sessions, Zero Quota Increases
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/wernervogels/" rel="noopener noreferrer"&gt;Werner Vogels&lt;/a&gt; talks about &lt;a href="https://thefrugalarchitect.com" rel="noopener noreferrer"&gt;the Frugal Architect&lt;/a&gt;: cost-aware design as a first-class engineering concern, not an afterthought. This project runs on my personal AWS account. No technical account manager. No need to request quota increases through a support plan. No need for using my "AWS Hero" Card.&lt;/p&gt;

&lt;p&gt;Nova 2 Sonic has a default service quota of 20 concurrent &lt;code&gt;InvokeModelWithBidirectionalStream&lt;/code&gt; requests per region (check your Service Quotas console under Amazon Bedrock for the exact current value). That's 20 simultaneous confessions per region before you hit throttling.&lt;/p&gt;

&lt;p&gt;Instead of requesting a quota increase, I built a queue-based routing system across all three available regions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REGIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-west-2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ap-northeast-1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;MAX_PER_REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pick_region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REGIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MAX_PER_REGION&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 regions × 20 concurrent sessions = 60 simultaneous confession sessions. On default quotas. No support ticket. No TAM call.&lt;/p&gt;

&lt;p&gt;The latency difference between regions is negligible for this use case. A confession guide isn't a trading bot. An extra 80ms of round-trip to Tokyo doesn't matter when the conversation has natural 2-second pauses between turns.&lt;/p&gt;

&lt;p&gt;Design around the constraints you have instead of asking for the constraints to be removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nova 2 Sonic Configuration That Matters
&lt;/h2&gt;

&lt;p&gt;Turn detection sensitivity set to &lt;code&gt;LOW&lt;/code&gt; for confession preparation. That's roughly a 2-second pause before the model responds. You want thoughtful pauses in this context, not rapid-fire conversation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;send_evt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sessionStart&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inferenceConfiguration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxTokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turnDetectionConfiguration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;endpointingSensitivity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Available values: &lt;code&gt;LOW&lt;/code&gt;, &lt;code&gt;MEDIUM&lt;/code&gt;, &lt;code&gt;HIGH&lt;/code&gt;. For most conversational use cases, &lt;code&gt;MEDIUM&lt;/code&gt; is fine. For reflective, thoughtful conversations, &lt;code&gt;LOW&lt;/code&gt; gives the user space to think.&lt;/p&gt;

&lt;p&gt;Connection limit is 8 minutes per WebSocket connection. For longer sessions, AWS provides a session continuation pattern in their samples.&lt;/p&gt;

&lt;p&gt;System prompt gotchas worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Without explicit instructions, the model repeats its welcome message on every turn. You need: "FIRST RESPONSE ONLY: Welcome with 'In the name of the Father...' AFTER THE FIRST RESPONSE: Do NOT repeat the welcome ever again."&lt;/li&gt;
&lt;li&gt;Hindi requires the speech instruction appended inline to the system prompt text, not as a separate content block. A separate block caused Hindi to be completely silent. No error. Just silence.&lt;/li&gt;
&lt;li&gt;Nova 2 Sonic sends &lt;code&gt;{ "interrupted": true }&lt;/code&gt; as JSON text during barge-in. Filter it server-side or your transcript gets polluted with raw JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Echo Cancellation: Still an Active Problem
&lt;/h2&gt;

&lt;p&gt;The iPhone speaker plays the AI's voice. The mic picks it up. The model hears itself and responds to its own echo. This is the hardest problem in the entire project.&lt;/p&gt;

&lt;p&gt;Four approaches, in order of desperation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flag-based mute when AI speaks. Problem: &lt;code&gt;contentEnd&lt;/code&gt; means the server finished &lt;em&gt;sending&lt;/em&gt;, not the speaker finished &lt;em&gt;playing&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Playback completion unmute using &lt;code&gt;scheduleBuffer&lt;/code&gt; completion handlers. Better timing, still some leakage.&lt;/li&gt;
&lt;li&gt;Send silence while muted. Zero-filled PCM frames keep the bidirectional stream alive while preventing echo from reaching the model.&lt;/li&gt;
&lt;li&gt;Prompt-level echo awareness: "You will hear your own voice echoed back. If you hear words identical to what you just said, that is YOUR OWN ECHO. IGNORE IT."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The official AWS Python sample never mutes the mic. Audio flows continuously in both directions. Nova 2 Sonic has built-in turn detection and handles echo internally. That works better on desktop where mic/speaker separation is cleaner. On a phone speaker, it's a different story.&lt;/p&gt;

&lt;p&gt;Current approach: silence-based muting + playback completion unmute + prompt-level echo awareness. Works about 90% of the time. The other 10% is still an active problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Economics
&lt;/h2&gt;

&lt;p&gt;Nova 2 Sonic pricing (per 1K tokens): $0.0034 speech input, $0.0136 speech output. That works out to roughly $0.02/min combined.&lt;/p&gt;

&lt;p&gt;A 5-minute session costs about $0.10. Not $1. Not $5. Ten cents.&lt;/p&gt;

&lt;p&gt;At $1.99 per session, after Apple's 30% cut ($1.39 net), that's about $1.29 profit per paid session. The margins are real.&lt;/p&gt;

&lt;p&gt;The freemium flow: 1 free minute (configurable via DynamoDB, no app update needed), then a paywall. Pay $1.99 to continue for up to 5 minutes. A 30-second grace period after the paywall gives users time to decide. The free minute costs about $0.02 to deliver. Even if nobody converts, the free tier costs almost nothing to run.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Per Session&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nova 2 Sonic cost (5 min)&lt;/td&gt;
&lt;td&gt;~$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User pays&lt;/td&gt;
&lt;td&gt;$1.99&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple's 30% cut&lt;/td&gt;
&lt;td&gt;-$0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Net to developer&lt;/td&gt;
&lt;td&gt;$1.39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Profit&lt;/td&gt;
&lt;td&gt;~$1.29&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Session recordings are AI audio only, stored locally on the user's device. Never on servers. The user can save and share via the standard iOS share sheet.&lt;/p&gt;

&lt;p&gt;Total AWS infrastructure cost for the backend? Lambda, DynamoDB, API Gateway, AgentCore Runtime. On a personal account with low traffic, we're talking single-digit dollars per month before any sessions even happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: AgentCore WebRTC
&lt;/h2&gt;

&lt;p&gt;On March 20, AWS announced &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/03/amazon-bedrock-webrtc/" rel="noopener noreferrer"&gt;WebRTC support for AgentCore Runtime&lt;/a&gt;. This is a big deal for this project.&lt;/p&gt;

&lt;p&gt;Right now, the audio path is: iPhone → WebSocket → AgentCore → Nova 2 Sonic. WebSocket works, but it's a text-based protocol carrying base64-encoded audio. Every audio frame gets encoded, wrapped in JSON, and decoded on the other end.&lt;/p&gt;

&lt;p&gt;WebRTC is purpose-built for real-time media. Binary audio frames. Built-in echo cancellation at the protocol level. Adaptive bitrate. Jitter buffers. All the things I've been fighting to implement manually in Swift.&lt;/p&gt;

&lt;p&gt;The migration path is straightforward since AgentCore Runtime supports both protocols on the same runtime. I can add a WebRTC endpoint alongside the existing WebSocket one and A/B test latency and echo cancellation quality on real devices.&lt;/p&gt;

&lt;p&gt;If WebRTC's built-in echo cancellation works well on iPhone speakers, that solves the hardest remaining problem in the entire project. That 10% failure rate on echo could drop to near zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;Verify audio end-to-end on day one. Inject a known sine wave, record what the model receives, compare. Would have saved hours of headache.&lt;/p&gt;

&lt;p&gt;Start with the classic Cognito flow. Don't even try enhanced flow with Bedrock. It won't work and the error messages won't tell you why.&lt;/p&gt;

&lt;p&gt;Build echo cancellation as a first-class feature, not an afterthought. On mobile, this is the hardest problem. Budget time for it.&lt;/p&gt;

&lt;p&gt;Use Docker assets (ECR) for AgentCore from the start. Code assets (S3) seem simpler to package but the cold start timeout makes them impractical for anything with dependencies.&lt;/p&gt;

&lt;p&gt;Design for multi-region from day one. The frugal routing across three regions was an afterthought that should have been the starting architecture. Default quotas are generous if you think horizontally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Point
&lt;/h2&gt;

&lt;p&gt;1.39 billion baptized Catholics worldwide. A sacrament that many want to practice but feel unprepared for.&lt;/p&gt;

&lt;p&gt;This isn't about replacing priests. It's about removing the anxiety barrier that keeps people from showing up in the first place. A 5-minute voice conversation that helps you organize your thoughts, in your own language, on your own time. For ten cents of compute.&lt;/p&gt;

&lt;p&gt;Building this was fast. The debugging was not. Every major bug was the invisible kind: plausible RMS values hiding garbage audio, silent timers on runloop-less threads, session policies you can't see in any console. The documentation had gaps. Echo cancellation on a phone speaker remains partially unsolved.&lt;/p&gt;

&lt;p&gt;Most of the code was written with &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro CLI&lt;/a&gt;. What would have taken weeks of back-and-forth between Swift, Python, and CDK was done in hours.&lt;/p&gt;

&lt;p&gt;But someone will open this app before their first confession in 20 years. And they'll feel a little less anxious walking in.&lt;/p&gt;

&lt;p&gt;That's worth ten cents. Now go build.&lt;/p&gt;

</description>
      <category>agentcore</category>
      <category>ios</category>
      <category>kiro</category>
      <category>aws</category>
    </item>
    <item>
      <title>I Turned Notion Into a Control Plane for my 18 OpenClaw AI Agents</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Sat, 07 Mar 2026 05:43:11 +0000</pubDate>
      <link>https://dev.to/aws-heroes/i-turned-notion-into-a-control-plane-for-my-18-openclaw-ai-agents-5624</link>
      <guid>https://dev.to/aws-heroes/i-turned-notion-into-a-control-plane-for-my-18-openclaw-ai-agents-5624</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt; just got an &lt;a href="https://aws.amazon.com/blogs/aws/introducing-openclaw-on-amazon-lightsail-to-run-your-autonomous-private-ai-agents/" rel="noopener noreferrer"&gt;Amazon Lightsail blueprint&lt;/a&gt;. No more Mac Minis. No more Raspberry Pis sitting on your desk acting as your AI agent server. Click deploy and you have an agent platform running in the cloud.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aws-samples/sample-host-openclaw-on-amazon-bedrock-agentcore" rel="noopener noreferrer"&gt;AWS samples&lt;/a&gt; also has an experimental (non-production) implementation that runs OpenClaw as per-user serverless containers on AgentCore Runtime. The serverless version is early, but the direction is clear.&lt;/p&gt;

&lt;p&gt;That means OpenClaw can now run in different places. A Raspberry Pi on my desk. A Lightsail instance in the cloud. Serverless containers on AgentCore or even on an EC2. Pick a flavor. (I didnt buy a Mac Mini)&lt;/p&gt;

&lt;p&gt;I run 18 agents on mine. These aren't toy demos. They solve problems I got tired of solving by hand.&lt;/p&gt;

&lt;p&gt;After re:Invent last year, every expo vendor on the floor started emailing me. Booth scans, follow-ups, drip campaigns. Unsubscribing from each one is death by a thousand clicks. So I built an unsubscribe agent. I don't give it access to my personal mailbox. I forward vendor spam to OpenClaw's own email inbox. It parses the email, finds the unsubscribe link, clicks it, and confirms. I set up one mail rule and forgot about it. 47 vendor lists cleared in two weeks.&lt;/p&gt;

&lt;p&gt;Then there's the train monitor. After peak hours, the next train home is an hour away. Miss it and you're standing on a cold platform for 60 minutes. The problem is trains don't always behave. Sometimes it arrives a minute early. Sometimes it switches platforms with no announcement. I was refreshing the train app constantly. The agent polls live train data and pushes me a notification when something changes. Platform switch, early arrival, cancellation. I get the update instead of checking.&lt;/p&gt;

&lt;p&gt;OpenClaw even built me a full SaaS-like newsletter platform "&lt;a href="https://theagenticengineer.waltsoft.net/" rel="noopener noreferrer"&gt;The Agentic Engineer&lt;/a&gt;". I wanted a weekly newsletter to keep me updated on the Agentic AI content that I am interested in - along with a platform for subscriber management, double opt-in, click tracking, A/B subject lines, archive pages with SEO, threaded comments, the works. Instead of stitching together Substack or Beehiiv or whatever, I pointed the ask to OpenClaw and let it go. CDK stacks, Lambda functions, DynamoDB tables, SES integration, CloudFront distribution — it scaffolded the entire thing. Then another agent writes and publishes the issues. The platform runs on autopilot. I haven't touched it in weeks. It has more features than most newsletter SaaS tools I've paid for, and it costs me about $2/month in AWS bills. An example of true SaaSpocalypse.&lt;/p&gt;

&lt;p&gt;Now multiply that by 18 agents, all running on cron schedules, and you hit the real problem of migrating or cloning your agentic work at 10X scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent Migration Problem
&lt;/h2&gt;

&lt;p&gt;Managing 18 agents was already a mess. SSH into a server. No single view other than the OpenClaw Dashboard. No way to pause an agent without editing config files or telegraming the OpenClaw. No full history of what ran, what failed, or how many tokens got burned.&lt;/p&gt;

&lt;p&gt;But with three deployment targets, a new problem showed up: how do you move your agents between them along with their identity and history?&lt;/p&gt;

&lt;p&gt;Each agent has a custom prompt, a personality file, tool configurations, cron schedules. My unsubscribe bot has mail parsing rules. My train monitor has API polling configs. 18 agents worth of state that lives in files on disk.&lt;/p&gt;

&lt;p&gt;Migrating that from a Raspberry Pi to a Lightsail blueprint by hand? Copying config files, re-editing cron tabs, testing each agent one by one? I'd rather stand on that cold train platform for an hour.&lt;/p&gt;

&lt;p&gt;I needed a control plane that was portable. Something that could snapshot my entire fleet, move it to a new instance, and bring everything back up. And I didn't want to run a database for it.&lt;/p&gt;

&lt;p&gt;So I built AgentOps. And I built it on Notion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnakgfi1o7zpr9zor4ml.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnakgfi1o7zpr9zor4ml.jpg" alt="AgentOps Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AgentOps turns Notion into the control plane for an entire OpenClaw agent fleet. Four Notion databases form the backbone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent Registry.&lt;/strong&gt; 18 OpenClaw agents, each a row. Name, type, status, schedule, config, last heartbeat. Change status to "paused" in Notion and the runtime stops dispatching to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswbdil4qhosqth5o5p5j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswbdil4qhosqth5o5p5j.jpg" alt="Agent Registry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Task Queue.&lt;/strong&gt; Every task with priority, status, assigned agent. Create a row in Notion, the OpenClaw runtime picks it up automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrphk6nqvmre1jzy7sjy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrphk6nqvmre1jzy7sjy.jpg" alt="Task Queue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run Log.&lt;/strong&gt; Every execution recorded. Input, output, duration, tokens used, errors. 78 runs tracked so far.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotopelje59zsxd2dhb7o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotopelje59zsxd2dhb7o.jpg" alt="Run Log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alerts.&lt;/strong&gt; Failures surface immediately. Acknowledge them with a checkbox click.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mi3qswdyped1uqhdx0x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mi3qswdyped1uqhdx0x.jpg" alt="Alerts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key design decision: Notion IS the database. No Postgres. No MongoDB. Every read and write goes through the Notion API. You control your OpenClaw agents by editing Notion pages.&lt;/p&gt;

&lt;p&gt;On top of that, AgentOps includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token analytics.&lt;/strong&gt; Per-agent breakdown, daily trends, top consumers. 128K+ tokens tracked across all OpenClaw agent runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flny6nw08cr22sxe8ffwk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flny6nw08cr22sxe8ffwk.jpg" alt="Token analytics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace sync.&lt;/strong&gt; Push your OpenClaw agent configuration files (prompts, personality, tools) to Notion. Edit them there. Pull changes back to your OpenClaw instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej6yz5u3bklw0vezr261.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej6yz5u3bklw0vezr261.jpg" alt="Workspace sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent tuning.&lt;/strong&gt; Bidirectional prompt sync. Edit an OpenClaw agent's prompt in Notion, apply it live with one click.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr49j94sx2acvs18id2mh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr49j94sx2acvs18id2mh.jpg" alt="Agent tuning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full backup.&lt;/strong&gt; Snapshot your entire OpenClaw agent fleet to a Notion page. Workspace files, prompts, cron definitions, agent registry. Restore anytime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F49u31fajtjh7vm8orhin.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F49u31fajtjh7vm8orhin.jpg" alt="Backup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fleet cloning.&lt;/strong&gt; Export your OpenClaw agent fleet as a portable JSON bundle. Import it on a fresh instance. Your entire AI operation, portable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this data lives directly in your Notion workspace. Agent Registry, Task Queue, Run Log, Alerts, Backups, Agent Prompts. No external database. Open Notion and you see everything.&lt;/p&gt;

&lt;p&gt;Three built-in agents ship with it (summarizer, code reviewer, sentiment analyzer) that work end-to-end through Notion without any external AI API keys. Create a task, watch it get dispatched, see results land in the Run Log.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/-JN3xmNUiiw"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/awsdataarchitect" rel="noopener noreferrer"&gt;
        awsdataarchitect
      &lt;/a&gt; / &lt;a href="https://github.com/awsdataarchitect/agentops" rel="noopener noreferrer"&gt;
        agentops
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Notion-powered control plane for OpenClaw AI agents — monitor, dispatch, tune, backup, and clone your agent fleet
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🤖 AgentOps — Notion-Powered Control Plane for OpenClaw Agent Fleets&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Notion MCP Challenge Entry&lt;/strong&gt; — Use Notion as the human-in-the-loop command center for managing &lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt; AI agents.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AgentOps turns your Notion workspace into a fully functional agent operations control plane. Monitor your OpenClaw fleet, dispatch tasks, track token usage, tune agent prompts, and backup your entire configuration — all through Notion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Humans stay in control.&lt;/strong&gt; Every agent, task, and configuration lives in Notion. Edit a page to pause an agent. Change a priority by updating a select field. Notion is the database.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📸 Screenshots&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Dashboard&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Real-time overview of your OpenClaw agent fleet — 18 agents, success rate, token usage, pipeline health, and recent activity.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/awsdataarchitect/agentops/screenshots/01-dashboard.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fawsdataarchitect%2Fagentops%2Fscreenshots%2F01-dashboard.jpg" alt="Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Agent Registry&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;All 18 OpenClaw agents with status, schedules, and one-click pause/resume. Filter by type: cron, monitor, heartbeat, subagent, or demo agents.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/awsdataarchitect/agentops/screenshots/02-agents.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fawsdataarchitect%2Fagentops%2Fscreenshots%2F02-agents.jpg" alt="Agent Registry"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Task Queue&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Priority-based task queue with status tracking. Create tasks manually or let the…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/awsdataarchitect/agentops" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Node.js, Express, React 19, Vite, Tailwind CSS v4, @notionhq/client&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│                  Notion                     │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │  Agent   │ │  Task    │ │  Run     │     │
│  │ Registry │ │  Queue   │ │  Log     │     │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘     │
│       │            │            │           │
│  ┌────┴────────────┴────────────┴─────┐     │
│  │         Notion API (MCP)           │     │
│  └────────────────┬───────────────────┘     │
└───────────────────┼─────────────────────────┘
                    │
        ┌───────────┴───────────┐
        │    AgentOps Server    │
        │  ┌─────────────────┐  │
        │  │  Agent Runtime  │  │
        │  │  (10s polling)  │  │
        │  └────────┬────────┘  │
        │  ┌────────┴────────┐  │
        │  │  Demo Agents    │  │
        │  │  • Summarizer   │  │
        │  │  • Code Review  │  │
        │  │  • Sentiment    │  │
        │  └─────────────────┘  │
        │  ┌─────────────────┐  │
        │  │  OpenClaw Fleet │  │
        │  │  (14 cron jobs) │  │
        │  └─────────────────┘  │
        └───────────┬───────────┘
                    │
        ┌───────────┴───────────┐
        │   React Dashboard     │
        │  • Fleet overview     │
        │  • Token analytics    │
        │  • Workspace sync     │
        │  • Agent tuning       │
        │  • Backup &amp;amp; clone     │
        └───────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6y22pbfnvucano2an9c3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6y22pbfnvucano2an9c3.jpg" alt="Notion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notion MCP is the entire persistence and control layer for OpenClaw agents. There is no other database. Here's how each piece works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Registry&lt;/strong&gt; (notion-create-pages, notion-update-page, notion-query-database-view)&lt;/p&gt;

&lt;p&gt;Every OpenClaw agent is a Notion database row. The runtime queries for active agents before dispatching. Pause an agent by changing its status select property. The runtime reads it on the next 10-second poll and skips it. Resume by switching back to "active." Zero config files touched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task Queue&lt;/strong&gt; (notion-create-pages, notion-query-database-view)&lt;/p&gt;

&lt;p&gt;Tasks are Notion rows with status, priority, and agent type. The runtime queries for pending tasks sorted by priority, matches them to active OpenClaw agents, updates status to "running," executes, then marks "completed" or "failed." You can create tasks directly in Notion and the system picks them up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run Log&lt;/strong&gt; (notion-create-pages)&lt;/p&gt;

&lt;p&gt;Every OpenClaw agent execution writes a detailed record: input, output, duration in milliseconds, tokens consumed, error messages. This feeds the token analytics dashboard and provides full audit history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alerts&lt;/strong&gt; (notion-create-pages, notion-update-page)&lt;/p&gt;

&lt;p&gt;When an OpenClaw agent fails, an alert row is created automatically. The "Acknowledged" checkbox lets operators dismiss alerts from Notion or the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workspace Sync&lt;/strong&gt; (notion-create-pages, notion-update-page)&lt;/p&gt;

&lt;p&gt;OpenClaw agent configuration files (personality, tools, prompts) are pushed to Notion as formatted pages. The markdown-to-blocks converter handles headings, paragraphs, lists, code blocks, and bold/italic annotations. Secrets are automatically redacted before sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Tuning&lt;/strong&gt; (notion-create-database, notion-create-pages, notion-fetch)&lt;/p&gt;

&lt;p&gt;A dedicated "Agent Prompts" database stores each OpenClaw agent's prompt. Edit in Notion's rich editor, pull changes back to disk, and apply live to the running OpenClaw instance. Bidirectional sync with diff detection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backup&lt;/strong&gt; (notion-create-pages, notion-fetch)&lt;/p&gt;

&lt;p&gt;Full OpenClaw fleet snapshots stored as Notion pages with toggle blocks containing workspace files, prompts, cron definitions, and agent registry data. Restore writes files back to disk from Notion content. Export as JSON for cloning to a fresh OpenClaw instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;The human-in-the-loop problem for AI agents is real. Most agent systems are black boxes. You deploy them and hope. Notion MCP turns Notion into a transparent control surface where non-technical operators can monitor, pause, configure, and audit OpenClaw agents using an interface they already know. No SSH. No config files. No dashboards that only engineers can read.&lt;/p&gt;

&lt;p&gt;But the portability angle is what I didn't expect to matter this much.&lt;/p&gt;

&lt;p&gt;OpenClaw is spreading. Lightsail blueprints. AgentCore serverless containers. Raspberry Pis. People are running their claws on different platforms, and they will keep moving between them as the options get better. The agents, prompts, schedules, and configs need to travel with them.&lt;/p&gt;

&lt;p&gt;AgentOps makes Notion the portable layer. Backup your Pi claw to Notion. Spin up a Lightsail blueprint. Import. Done. All 18 agents, their prompts, schedules, and configs. Moved in minutes, not hours.&lt;/p&gt;

&lt;p&gt;18 agents. All runs logged. All tokens tracked. Four Notion databases. Zero external databases. Three deployment platforms. One control plane.&lt;/p&gt;

&lt;p&gt;Your Notion workspace becomes the operating system for your claw. 🦞&lt;/p&gt;

</description>
      <category>notionchallenge</category>
      <category>openclaw</category>
      <category>mcp</category>
      <category>devchallenge</category>
    </item>
    <item>
      <title>AgentBoard: A Discovery Platform for the Agentic AI Community</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Sat, 28 Feb 2026 01:14:21 +0000</pubDate>
      <link>https://dev.to/vivek-aws/agentboard-a-discovery-platform-for-the-agentic-ai-community-30ep</link>
      <guid>https://dev.to/vivek-aws/agentboard-a-discovery-platform-for-the-agentic-ai-community-30ep</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/weekend-2026-02-28"&gt;DEV Weekend Challenge: Community&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Community
&lt;/h2&gt;

&lt;p&gt;I write for &lt;a href="https://theagenticengineer.beehiiv.com" rel="noopener noreferrer"&gt;The Agentic Engineer&lt;/a&gt;, a weekly newsletter tracking the agentic AI space. The readers are builders. They ship autonomous agents, multi-agent workflows, and AI tools for a living.&lt;/p&gt;

&lt;p&gt;The number one question I get: &lt;strong&gt;"Which framework should I use?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are 15+ major agent frameworks right now. New ones launch weekly. You either scroll GitHub trending, ask Twitter, or hope someone wrote a comparison post this month. There's no single place to browse, compare, and discover what's out there.&lt;/p&gt;

&lt;p&gt;That's the community AgentBoard serves: agentic AI builders who need a front door to the tools they're building with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://natearcher-ai.github.io/agentboard/" rel="noopener noreferrer"&gt;AgentBoard&lt;/a&gt; is an open directory for AI agents, frameworks, and tools. Think Product Hunt, but only for agentic AI.&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browse 15 pre-seeded agents across 8 categories (dev tools, automation, research, infrastructure, and more)&lt;/li&gt;
&lt;li&gt;Search by name or filter by category&lt;/li&gt;
&lt;li&gt;Sort by GitHub stars, upvotes, or newest&lt;/li&gt;
&lt;li&gt;Click into any agent for the full breakdown: tech stack, creator, description, links&lt;/li&gt;
&lt;li&gt;Upvote and bookmark your favorites (persists locally)&lt;/li&gt;
&lt;li&gt;Submit your own agent through a simple form&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No login. No backend. Everything runs client-side with localStorage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live site:&lt;/strong&gt; &lt;a href="https://natearcher-ai.github.io/agentboard/" rel="noopener noreferrer"&gt;natearcher-ai.github.io/agentboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The home page shows community stats and featured agents. The Discover page is the core: real-time search, category filter tabs, and three sort modes. Click any card for the full agent profile. Hit Submit to add your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/natearcher-ai" rel="noopener noreferrer"&gt;
        natearcher-ai
      &lt;/a&gt; / &lt;a href="https://github.com/natearcher-ai/agentboard" rel="noopener noreferrer"&gt;
        agentboard
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AgentBoard — Community-driven AI agent discovery platform. Browse, share, and celebrate AI agents built by the community.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;AgentBoard 🤖&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Community-driven AI agent discovery platform.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Browse, share, and celebrate the AI agents, skills, and tools shaping the future of autonomous AI.&lt;/p&gt;
&lt;p&gt;🔗 &lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://natearcher-ai.github.io/agentboard/" rel="nofollow noopener noreferrer"&gt;natearcher-ai.github.io/agentboard&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is AgentBoard?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;AgentBoard is an open directory for the agentic AI community. Think Product Hunt meets Awesome Lists — specifically for AI agents and tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🔍 Browse &amp;amp; search a curated directory of AI agents&lt;/li&gt;
&lt;li&gt;🏷️ Filter by category (dev tools, automation, research, etc.)&lt;/li&gt;
&lt;li&gt;📋 Detailed agent profiles with tech stack, links, and descriptions&lt;/li&gt;
&lt;li&gt;➕ Submit your own agents via a simple form&lt;/li&gt;
&lt;li&gt;⬆️ Upvote and bookmark your favorites&lt;/li&gt;
&lt;li&gt;📊 Community stats dashboard&lt;/li&gt;
&lt;li&gt;🌙 Beautiful dark theme with smooth animations&lt;/li&gt;
&lt;li&gt;📱 Fully responsive (mobile + desktop)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Screenshots&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Home&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The landing page features a hero section, community stats, and featured agents.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Discover&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Filterable, searchable directory with category tabs and sort options.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Submit&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Clean form to contribute your own AI agent to the directory.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/natearcher-ai/agentboard" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React 19, Vite, Tailwind CSS v4, React Router, Lucide icons.&lt;/p&gt;

&lt;p&gt;I went with a static SPA on purpose. No database means no hosting costs, no auth complexity, and anyone can fork it and run it locally in 30 seconds. The seed data lives in a single JS file. Adding a new agent is one object in an array.&lt;/p&gt;

&lt;p&gt;The UI is dark-themed with a purple/blue gradient palette. Cards have hover animations. The discover page supports real-time search, category tabs, and three sort modes. The submit form validates inputs and drops you straight into the directory after submission.&lt;/p&gt;

&lt;p&gt;Deployed via GitHub Actions to GitHub Pages. Push to main, site updates in under a minute.&lt;/p&gt;

&lt;p&gt;MIT licensed. PRs welcome.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Promised an iOS App. Kiro CLI and Xcode MCP Built It in Hours.</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Tue, 24 Feb 2026 19:54:46 +0000</pubDate>
      <link>https://dev.to/aws-heroes/i-promised-an-ios-app-kiro-cli-and-xcode-mcp-built-it-in-hours-519l</link>
      <guid>https://dev.to/aws-heroes/i-promised-an-ios-app-kiro-cli-and-xcode-mcp-built-it-in-hours-519l</guid>
      <description>&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/aws-heroes/ive-been-a-costco-member-for-25-years-last-month-i-built-an-ai-agent-to-get-my-money-back-3a0g"&gt;previous blog post&lt;/a&gt;, I shared a weekend vibe coding project. An AI-powered Costco Receipt Scanner and Price Match Agent. Completely serverless with Amazon Bedrock AgentCore. Nova AI parsing receipts. CDK deploying everything. Weekly email reports with price adjustment opportunities.&lt;/p&gt;

&lt;p&gt;My post on &lt;a href="https://www.linkedin.com/posts/activity-7428223573019922432-K0cC?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAAVf9YBt5RWXCGBAPvftb5YcBteu3f-__0" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; got more traction than anything I’d ever shared. More views than all my previous posts combined, which says more about my previous posts than this one. The blog was also featured in &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-3h5k"&gt;DEV’s Top 7 posts of the week&lt;/a&gt;, along with a Top-7 badge which got automatically added to my &lt;a href="https://dev.to/vivek-aws"&gt;dev.to profile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also promised a native iOS app for the frontend. This is that follow-up. But the story took a turn I didn't expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  10 Years Apart
&lt;/h2&gt;

&lt;p&gt;In 2016, I built my first iOS app as a side project while learning Swift, which had recently debuted as Apple’s programming language for iOS. I outsourced a complex functionality to a developer for around $500. The whole development cycle took months but that is how I learn something new by building it myself. Getting the iOS app approved by Apple was its own ordeal if you know what I mean.&lt;/p&gt;

&lt;p&gt;In February 2026, Apple released Xcode 26.3 with MCP support. I pointed Kiro CLI (using latest Claude Opus 4.6 model) at Xcode through the MCP bridge and built the entire iOS app in hours.&lt;/p&gt;

&lt;p&gt;Not a toy. Not a single-screen demo. A full four-tab app with receipt scanning, deal tracking, AI-powered price match analysis with streaming responses, and a settings screen with BYOI configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Xcode MCP Bridge
&lt;/h2&gt;

&lt;p&gt;Apple's &lt;a href="https://developer.apple.com/documentation/xcode/giving-agentic-coding-tools-access-to-xcode" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; explains how to give agentic coding tools access to Xcode. The Kiro (IDE + CLI) setup is just three lines in your MCP config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"xcode-tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xcrun"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mcpbridge"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prerequisites: Xcode 26.3 or later. That's it.&lt;/p&gt;

&lt;p&gt;The bridge exposes about 20 MCP tools to the AI agent. BuildProject runs incremental builds in 0.9 seconds. XcodeRead, XcodeWrite, and XcodeUpdate handle file operations directly in the project structure. XcodeGrep searches code. GetBuildLog surfaces compiler errors. RenderPreview shows SwiftUI previews. RunSomeTests executes test suites.&lt;/p&gt;

&lt;p&gt;The development loop changes completely. I describe what I want in natural language. The agent writes Swift code, triggers a build through MCP, reads the compiler errors, fixes them, rebuilds. The whole cycle takes seconds.&lt;/p&gt;

&lt;p&gt;Here's the actual prompt that kicked it off:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build me an iOS app using Amplify SDK for Swift, leverage all the backend APIs we already have. Use the Xcode MCP tools. Make it professional and state of the art. I want to publish it, but I don't want to use my AWS infra. Let the user put their API endpoint into Settings, and everything gets picked up from there. That way whoever deploys the stack can use the app from their own infra. I don't worry about scaling or charging them for tokens by being just an Uber or Airbnb of this thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. That was the prompt. Kiro CLI took it from there with a few iterations and refinements to polish it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same Backend, New Frontend
&lt;/h2&gt;

&lt;p&gt;The original post described the full serverless backend: Lambda running FastAPI, API Gateway with JWT auth, DynamoDB for receipts and deals, S3 for PDF storage, Bedrock for Nova AI parsing and analysis, AgentCore Runtime for the weekly agent, EventBridge Scheduler firing every Friday at 9pm, SES for email reports.&lt;/p&gt;

&lt;p&gt;All of that stays exactly the same. The iOS app just connects to the existing API Gateway endpoint. Same Cognito auth. Same routes. Same everything.&lt;/p&gt;

&lt;p&gt;I originally planned to use Amplify Library for Swift. I tried it. Build times jumped to 18 seconds. The SDK pulled in a lot of dependencies I didn't need for this use case.&lt;/p&gt;

&lt;p&gt;So I ripped it out. Zero third-party packages. Pure URLSession for API calls. Direct Cognito REST API calls for authentication using USER_PASSWORD_AUTH flow. Build time dropped to 0.9 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  BYOI: Bring Your Own Infrastructure
&lt;/h2&gt;

&lt;p&gt;This is the part that changed my thinking about app distribution.&lt;/p&gt;

&lt;p&gt;CostScanner is not a SaaS. I don't host anything for users. I don't run servers. I don't store anyone's data. Note: I had to change the name with no Costco word in it due to obvious trademark and app publising reasons.&lt;/p&gt;

&lt;p&gt;Users deploy their own AWS CDK stack. Three stacks: one for DynamoDB tables and S3 bucket, one for Lambda and API Gateway and Cognito, one for the weekly AgentCore agent. One &lt;code&gt;cdk deploy&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install
&lt;/span&gt;&lt;span class="nv"&gt;NOTIFY_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;you@example.com ./deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then they paste their API Gateway URL into the app's Settings screen. The app calls a &lt;code&gt;/api/config&lt;/code&gt; endpoint, fetches the Cognito pool details and credentials from Secrets Manager, signs in programmatically, and starts working.&lt;/p&gt;

&lt;p&gt;No sign-in screen. No account/user creation flow. No "forgot password" emails. The infrastructure IS the account/user. I would love to see a "sign-in with AWS" or "Builder ID" API from Amazon for the login flows!&lt;/p&gt;

&lt;p&gt;The privacy policy literally says "we collect nothing." Because we don't. Every receipt, every deal, every AI analysis result lives in the user's own AWS account. They can &lt;code&gt;cdk destroy&lt;/code&gt; and everything disappears.&lt;/p&gt;

&lt;p&gt;Here's what this means for scaling: nothing. I don't worry about it. Unlike Airbnb or Uber, I don't provision capacity for peak load. I don't manage database connections. I don't handle multi-tenant data isolation. Each user's infrastructure scales independently through AWS serverless services. If one user uploads 500 receipts, that's their Tokens, Lambda and their DynamoDB handling it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;15 Swift files&lt;/li&gt;
&lt;li&gt;0 third-party dependencies&lt;/li&gt;
&lt;li&gt;0.9 second incremental builds&lt;/li&gt;
&lt;li&gt;3 CDK stacks&lt;/li&gt;
&lt;li&gt;Under $1 per month AWS cost per user&lt;/li&gt;
&lt;li&gt;Bedrock Nova tokens: $0.10-0.20 per week&lt;/li&gt;
&lt;li&gt;Lambda, DynamoDB, API Gateway, S3: free tier for personal use&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;The original backend and web app were built in hours with Kiro CLI. The iOS frontend? Even faster, thanks to the MCP bridge. The difference isn't just speed. It's the feedback loop.&lt;/p&gt;

&lt;p&gt;With the MCP bridge, the AI agent doesn't just write code. It builds it, reads the errors, and fixes them. I'm not copying compiler output into a chat window. The agent sees what Xcode sees. It knows when the build succeeds. It knows when a type doesn't conform to a protocol. It fixes it and moves on.&lt;/p&gt;

&lt;p&gt;The BYOI model is something I want to explore more. For personal tools and utilities, the SaaS model adds complexity that nobody asked for. User management, billing, support, scaling, compliance. BYOI sidesteps all of it. The user owns their stack. You ship the app and the CDK templates. Done.&lt;/p&gt;

&lt;p&gt;Ten years between my first iOS app and this one. Back then I paid $500 to outsource functionality and spent months shipping it. This time I used Kiro Pro at $20/month, connected through IAM Identity Center (IdC) login to seamlessly use my AWS credits (thanks to the AWS Heroes program). The whole iOS app was done in hours. &lt;/p&gt;

&lt;p&gt;In ten years, almost everything about building software feels completely different. The tools have evolved. The cost of building has significantly dropped. Even how software reaches users feels different now.&lt;/p&gt;

&lt;p&gt;But the hot dog combo is still $1.50 and the rotisserie chicken is still $7.99 (in Canada). Now I scan my receipt before I leave the Costco parking lot!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❤️ Built with &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro CLI&lt;/a&gt;, Amazon Bedrock, AWS CDK, and Apple's Xcode MCP bridge.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🔗 Full source code: &lt;a href="https://github.com/awsdataarchitect/costco-price-match" rel="noopener noreferrer"&gt;github.com/awsdataarchitect/costco-price-match&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 Download CostScanner: &lt;a href="https://apps.apple.com/ca/app/costscanner/id6759347927" rel="noopener noreferrer"&gt;App Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What are you going to build with Kiro CLI and Xcode MCP bridge ? Let me know in the comments.&lt;/p&gt;

</description>
      <category>kiro</category>
      <category>ios</category>
      <category>mcpbridge</category>
      <category>xcode</category>
    </item>
    <item>
      <title>I've Been a Costco Member for 25 Years. Last Month I Built an AI Agent to Get My Money Back</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Fri, 13 Feb 2026 23:45:21 +0000</pubDate>
      <link>https://dev.to/aws-heroes/ive-been-a-costco-member-for-25-years-last-month-i-built-an-ai-agent-to-get-my-money-back-3a0g</link>
      <guid>https://dev.to/aws-heroes/ive-been-a-costco-member-for-25-years-last-month-i-built-an-ai-agent-to-get-my-money-back-3a0g</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I've been a Costco member since 2001. That's 25 years of bulk toilet paper, ziplock bags, and the occasional impulse buy of a 48-pack of batteries I definitely didn't need.&lt;/p&gt;

&lt;p&gt;Over those years, one thing has kept me loyal: their customer service. It's genuinely good. It reminds me of Amazon's Customer Obsession Leadership Principle, where the customer is the starting point and you work backwards from there. Costco lives that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkjj73f12l0fwigibonl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkjj73f12l0fwigibonl.png" alt="costco" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern I Couldn't Ignore
&lt;/h2&gt;

&lt;p&gt;Here's something that kept happening to me. I'd buy a jacket for $24.99 on a Tuesday. The following week, I'd walk past the same jacket with a new price tag: $5.00 off. I'd buy a bag of dumplings for $14.99. Two weeks later, on sale for $11.99. This happened over and over. I started to wonder if Costco was personally timing their sales around my shopping trips.&lt;/p&gt;

&lt;p&gt;Costco has a price adjustment policy. If something you bought goes on sale within 30 days, you can go to the membership counter and get the difference back. The problem is you have to know it went on sale. You have to remember what you paid. You have to dig up the receipt. And you have to actually go do it before the 30 days are up.&lt;/p&gt;

&lt;p&gt;I never did any of that. I just ate the difference every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I Built a Thing
&lt;/h2&gt;

&lt;p&gt;I'm a builder. When I see a repetitive problem, I want to automate it. So I built an AI-powered Costco Receipt Scanner &amp;amp; Price Match Agent that does the whole thing for me. Completely Serverless with Amazon Bedrock AgentCore!&lt;/p&gt;

&lt;p&gt;Here's what it does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I upload my receipt PDFs (from my phone, from email, wherever)&lt;/li&gt;
&lt;li&gt;Amazon Nova AI parses every line item, price, item number, and whether I already got a temporary price drop&lt;/li&gt;
&lt;li&gt;Scrapers pull current deals from the web and Costco coupon book&lt;/li&gt;
&lt;li&gt;An AI agent cross-references my purchases against every active deal and tells me exactly which items dropped in price, how much I'd save, and what to say at the counter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole thing runs on AWS. FastAPI backend, DynamoDB for storage, S3 for receipt PDFs, Bedrock for the AI, and a web UI I can hit from my laptop or phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Weekly Agent
&lt;/h2&gt;

&lt;p&gt;I didn't want to manually check every week. So I built and deployed an Amazon Bedrock AgentCore agent with Strands SDK that runs automatically every Friday at 9 PM. It scrapes all the deal sources, runs the analysis across every receipt I've uploaded, and emails me a formatted HTML report via SES.&lt;/p&gt;

&lt;p&gt;The report has two sections. The first table shows price adjustment opportunities: items I paid full price for that are now on sale, with the exact savings per item. The second table shows items where Costco already applied a Temporary Price Drop (TPD) at checkout, so I can see what I saved without doing anything. Every item links back to the actual deal post so I can verify the prices myself, and every receipt reference is a presigned S3 link to the original PDF.&lt;/p&gt;

&lt;p&gt;Friday night I get an email. Saturday morning I walk into Costco with my receipts. Done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlxffv7fxl94ngrcdwxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlxffv7fxl94ngrcdwxl.png" alt="email_report" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time it ran, it found $9 in price adjustments I would have missed and confirmed $18 in TPD savings I didn't even know I'd gotten. Not life-changing money, but it adds up when it happens every week.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;For anyone who wants to look under the hood:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7u7r9e6kkgyajc3h49h4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7u7r9e6kkgyajc3h49h4.png" alt="Architecture Diagram" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Single HTML file hosted on AWS Amplify, with Cognito authentication. Same file works locally during development with no auth. Environment-aware through a config.js that gets generated at deploy time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API&lt;/strong&gt;: API Gateway HTTP API with Cognito JWT authorizer, backed by a Lambda function running the FastAPI app via Mangum. The analysis endpoint streams results back to the browser in real time so you can watch the AI think through each item match as it happens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt;: Amazon Nova models for receipt parsing (OCR) and price match analysis. Nova 2 Lite for standard parsing, Nova Premier for complex receipts that need a second pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: AgentCore Runtime runs the weekly agent inside a container. EventBridge Scheduler triggers it using a universal target (&lt;code&gt;aws-sdk:bedrockagentcore:invokeAgentRuntime&lt;/code&gt;) that calls AgentCore directly with zero Lambda functions in between. The agent scans deals, runs analysis, converts the markdown report to inline-styled HTML, and sends it through SES. The SES email identity is created by CDK on first deploy and sends a verification email automatically. One schedule, one container, one email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: DynamoDB for receipts and deals, S3 for receipt PDFs with presigned URLs for secure access from emails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: Everything defined in CDK (TypeScript) across three stacks. Repeatable, immutable, deploy to any region.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The flow for the weekly scan looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcr4gouor1r6cubbqksfz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcr4gouor1r6cubbqksfz.png" alt="weekly_agent" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing worth calling out: EventBridge Scheduler's universal target for AgentCore is undocumented as of this writing. I found it by looking at the supported SDK targets and guessing the ARN format. It works, but the scheduler reports the invocation as failed even when it succeeds (the streaming response confuses its success detection). Setting retries to zero prevents duplicate emails. I learned this the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Costs
&lt;/h2&gt;

&lt;p&gt;Here's what the project cost me in us-west-2 over the first two weeks (Feb 1-13), including all development and testing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Bedrock (Nova 2 Lite)&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;Receipt parsing + price match analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Bedrock AgentCore&lt;/td&gt;
&lt;td&gt;$0.23&lt;/td&gt;
&lt;td&gt;Container runtime for weekly agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon DynamoDB&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;td&gt;Receipts + deals tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon ECR&lt;/td&gt;
&lt;td&gt;$0.01&lt;/td&gt;
&lt;td&gt;Docker image storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Gateway&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Amplify&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Lambda&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon SES&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon S3&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.73&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Under a dollar for two weeks of building and testing. In steady state (one weekly scan, a few receipt uploads), expect roughly $0.10-0.20/week. Lambda, SES, DynamoDB, API Gateway, and Amplify all fall within free tier for personal use. Bedrock has no free tier, but Nova 2 Lite is cheap at $0.32 per million input tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Most of this project was written with &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro CLI&lt;/a&gt;, Amazon's AI coding assistant. What would have taken weeks of wiring up CDK stacks, debugging IAM policies, and figuring out EventBridge Scheduler's undocumented universal targets was done in a few hours of back-and-forth. I described what I wanted, Kiro wrote the code, I tested it, we iterated. The entire CDK infrastructure, the agent, the streaming API, the email converter, all of it.&lt;/p&gt;

&lt;p&gt;A few things that tripped us up along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Costco receipt abbreviations are wild. "CKN/VEG DUMP" is dumplings. "T TURTLENECK" is a sweater. Nova handles it well, but I added a two-tier system where Nova Premier reparses anything Nova Lite struggles with.&lt;/li&gt;
&lt;li&gt;Deduplication matters. Two of the same item should both show up, but each should only match the best deal. Tracking by receipt position solved this.&lt;/li&gt;
&lt;li&gt;TPD (Temporary Price Drop) detection was a late addition that turned out to be one of the most useful features. Costco applies these at checkout automatically. The scanner picks them up and shows what you saved without asking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploy It Yourself
&lt;/h2&gt;

&lt;p&gt;Everything deploys through CDK. Three stacks, one command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AWS CLI configured with credentials&lt;/li&gt;
&lt;li&gt;Node.js 18+ and npm&lt;/li&gt;
&lt;li&gt;Docker running (for Lambda and AgentCore container builds)&lt;/li&gt;
&lt;li&gt;Python 3.12+&lt;/li&gt;
&lt;li&gt;A verified email address in Amazon SES (the region you're deploying to)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run Locally
&lt;/h3&gt;

&lt;p&gt;You can run the whole thing on your laptop without deploying anything except the DynamoDB tables and S3 bucket (which the Common stack creates).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a virtual environment and install dependencies&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Run the app&lt;/span&gt;
./run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts FastAPI on &lt;code&gt;http://localhost:8000&lt;/code&gt;. The web UI at &lt;code&gt;static/index.html&lt;/code&gt; works locally without Cognito auth. Just open the HTML file in your browser and point it at localhost. The &lt;code&gt;run.sh&lt;/code&gt; script sets the default env vars (region, table names, bucket) so you don't need to configure anything if you deployed the Common stack with defaults.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbch4kvbgahraimvpfn07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbch4kvbgahraimvpfn07.png" alt="ui1" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4qgar63i2l3fmqpfisj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4qgar63i2l3fmqpfisj.png" alt="ui2" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone and install CDK dependencies&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;costco-scanner/infra
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Deploy everything (Lambda, Amplify, API Gateway, Cognito, DynamoDB, S3)&lt;/span&gt;
&lt;span class="c"&gt;# notifyEmail: your email address for weekly reports (SES verification sent on first deploy)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; .. &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./deploy.sh

&lt;span class="c"&gt;# Deploy the weekly agent (optional, requires a verified SES email)&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx cdk deploy CostcoScannerAgentCore &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;notifyEmail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-email@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--require-approval&lt;/span&gt; never
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;region&lt;/code&gt; context parameter controls where everything goes. The &lt;code&gt;notifyEmail&lt;/code&gt; parameter is the email that receives the weekly report from the AgentCore agent. On first deploy, CDK creates an SES identity for that email and sends a verification link. Click it once and the weekly reports start flowing.&lt;/p&gt;

&lt;p&gt;After deploy, CDK outputs the Amplify URL, API endpoint, and Cognito pool details. The AgentCore stack also creates an SES email identity for the &lt;code&gt;notifyEmail&lt;/code&gt; address, which triggers a verification email. Click the link in that email, and the weekly reports start working. Subsequent deploys won't re-trigger verification. Create a Cognito user through the AWS console or CLI, then log in to the web UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleanup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Destroy the AgentCore stack first (it depends on Common)&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx cdk destroy CostcoScannerAgentCore &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;notifyEmail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-email@example.com

&lt;span class="c"&gt;# Destroy Amplify + API stack&lt;/span&gt;
npx cdk destroy CostcoScannerAmplify &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2

&lt;span class="c"&gt;# Destroy shared resources (DynamoDB, S3, ECR) last&lt;/span&gt;
npx cdk destroy CostcoScannerCommon &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;S3 buckets and DynamoDB tables have &lt;code&gt;RemovalPolicy.DESTROY&lt;/code&gt; set, so they'll clean up with the stack. ECR repos too. If you want to keep your receipt data, back up the DynamoDB tables before destroying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source
&lt;/h2&gt;

&lt;p&gt;I'm making this open source. The code is available on &lt;a href="https://github.com/awsdataarchitect/costco-price-match" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you're a Costco member who's tired of leaving money on the table, clone it, deploy it, and start getting your price adjustments.&lt;/p&gt;

&lt;p&gt;The CDK stacks mean you can deploy the entire infrastructure to your own AWS account with a single command. Upload your receipts, let the agent do its thing, and walk into Costco knowing exactly what you're owed.&lt;/p&gt;

&lt;p&gt;If you're a developer who wants to learn how to build AI agents on AWS, this is a real working example. Not a toy demo. Not a chatbot that tells you the weather. A thing that actually saves you money every week.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm building a native iOS app using Amplify Library for Swift, so I can snap a photo of my receipt right at the checkout and upload it on the spot. Same Cognito auth, same API, same backend. Just a better experience on the phone.&lt;/p&gt;

&lt;p&gt;25 years of Costco membership. Thousands of dollars in missed price adjustments. One AI agent to make sure that never happens again.&lt;/p&gt;

&lt;p&gt;The hot dog combo is still $1.50 and the rotisserie chicken is still $7.99. Some things never change.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>kiro</category>
      <category>amplify</category>
    </item>
    <item>
      <title>How AWS Support Saved Me $530 (And Why You Should Check Your Quick Suite Settings Right Now)</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Wed, 11 Feb 2026 03:50:19 +0000</pubDate>
      <link>https://dev.to/aws-heroes/how-aws-support-saved-me-530-and-why-you-should-check-your-quick-suite-settings-right-now-3fjk</link>
      <guid>https://dev.to/aws-heroes/how-aws-support-saved-me-530-and-why-you-should-check-your-quick-suite-settings-right-now-3fjk</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Forgot to turn off a promo feature. Got hit with $530 in charges. AWS Support waived it all. Here's the full story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;From October 9, 2025 to January 31, 2026, I was heavily using Amazon Quick Suite Research during its promotional period. Amazon Quick Suite is an Agentic AI Teammate, a PhD-level researcher, a business analyst, and an automation expert in one workspace. The timing was perfect because I was preparing my AWS re:Invent presentation, and having access to custom datasets across AWS integrations made a huge difference with research quality. Being able to run evaluations against my own data helped me fine-tune everything before going on stage.&lt;/p&gt;

&lt;p&gt;If you want to see what I was working on: &lt;br&gt;


  &lt;iframe src="https://www.youtube.com/embed/-KDsJxHTPxg"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  The Oops Moment
&lt;/h2&gt;

&lt;p&gt;February rolls around. I forgot to turn off Admin Pro after the promotional period ended.&lt;/p&gt;

&lt;p&gt;Suddenly there's an extra $500+ charge on my bill. The promotional waiver for the Amazon Q in QuickSight infrastructure fee ($250/month) had ended on January 31, 2026. Plus there were Reader Capacity Pack charges I wasn't expecting.&lt;/p&gt;

&lt;p&gt;Here's the thing about Quick Suite pricing that caught me off guard: during the promo period, Admin Pro was only $40/month. But once the promotional period ends, you're also on the hook for the mandatory Amazon Q in QuickSight fee. That's a significant jump (++ $250/month extra with Admin Pro user) if you're not paying attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Support Came Through
&lt;/h2&gt;

&lt;p&gt;I reached out to AWS support. Keep in mind I'm on the free Basic support plan. No Business Support+ or Enterprise plan, no dedicated account manager, nothing fancy.&lt;/p&gt;

&lt;p&gt;They credited me the full $530:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$500 for the QuickSight capacity reader pack and Amazon Q charges&lt;/li&gt;
&lt;li&gt;$30 for additional user charges from January (accidently activated)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've worked with a lot of cloud providers. Getting charges waived when you're on a free support tier? That's a rare to find customer obsession these days. The fact that I got proactively alerted by AWS Budgets and CloudWatch alarms before the charges even hit my card made the whole conversation easier. &lt;/p&gt;

&lt;h2&gt;
  
  
  What Triggers the Amazon Q Fee
&lt;/h2&gt;

&lt;p&gt;This is the part I wish I'd understood earlier. The $250/month fee kicks in when your account has ANY of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pro users (Author Pro, Reader Pro, or Admin Pro)&lt;/li&gt;
&lt;li&gt;Topics created&lt;/li&gt;
&lt;li&gt;Dashboards with Q&amp;amp;A enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So even if you're not actively using the generative BI features, having a Pro user sitting there will trigger the charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Avoid This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you want to keep Pro but stop the Q fee:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to QuickSight Console &amp;gt; Topics and delete any Q Topics&lt;/li&gt;
&lt;li&gt;Check your dashboards and disable Q&amp;amp;A on each one&lt;/li&gt;
&lt;li&gt;Save the dashboards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But here's the catch: if you keep Admin Pro, you'll still pay the $250/month Q enablement fee. The Q fee is bundled with Pro subscriptions. You can't separate them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to avoid the Q fee entirely:&lt;/strong&gt;&lt;br&gt;
Downgrade from Pro to a regular Reader or non-Pro user type. You lose the Pro authoring capabilities but you also lose the $250/month charge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To cancel Reader Capacity Pack:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;QuickSight Console &amp;gt; Profile icon &amp;gt; Manage QuickSight&lt;/li&gt;
&lt;li&gt;Left nav &amp;gt; Manage Subscriptions&lt;/li&gt;
&lt;li&gt;Find Reader Capacity Pack (500 sessions)&lt;/li&gt;
&lt;li&gt;Click "Switch to user pricing"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Changes take effect the following month.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Billing Pattern That Tripped Me Up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;December 2025: No Q fee (promotional waiver active)&lt;/li&gt;
&lt;li&gt;January 2026: No Q fee (promotional waiver still active)
&lt;/li&gt;
&lt;li&gt;February 2026: $67.34 Q fee (prorated, promo ended January 31)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you enabled Pro users after October 9, 2025 (the Quick Suite launch date), your promotional period also ended January 31, 2026. Check your February bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;Amazon Quick Suite is genuinely powerful for AI evaluation and research work. The ability to use custom datasets across AWS integrations helped me prepare for re:Invent in ways I couldn't have done otherwise using either Perplexity Deep research or ChatGPT Deep research mode.&lt;/p&gt;

&lt;p&gt;But watch your billing. Set up AWS Budgets alerts. Set up CloudWatch alarms. And if something goes wrong, reach out to support. Even on the Basic plan, they might surprise you.&lt;/p&gt;

&lt;p&gt;Full opt-out instructions: &lt;a href="https://docs.aws.amazon.com/quicksuite/latest/userguide/generative-bi-opt-out.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/quicksuite/latest/userguide/generative-bi-opt-out.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Documentation
&lt;/h2&gt;

&lt;p&gt;★ &lt;strong&gt;Amazon Quick Suite Pricing:&lt;/strong&gt; &lt;a href="https://aws.amazon.com/quicksuite/pricing/" rel="noopener noreferrer"&gt;https://aws.amazon.com/quicksuite/pricing/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;★ &lt;strong&gt;Amazon Quick Suite User Types:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/quicksuite/latest/userguide/user-types.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/quicksuite/latest/userguide/user-types.html&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;★ &lt;strong&gt;Amazon Quick Suite Editions:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/quicksuite/latest/userguide/editions.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/quicksuite/latest/userguide/editions.html&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;★ &lt;strong&gt;Configure Quick Suite Subscriptions:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/quicksuite/latest/userguide/managing-subscriptions-configure.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/quicksuite/latest/userguide/managing-subscriptions-configure.html&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;★ &lt;strong&gt;Quick Suite User Guide:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/quicksuite/latest/userguide/" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/quicksuite/latest/userguide/&lt;/a&gt; &lt;/p&gt;

</description>
      <category>quick</category>
      <category>q</category>
    </item>
    <item>
      <title>Building Roblox Games with Kiro: A Spec-Driven Development Approach</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Sat, 18 Oct 2025 02:26:54 +0000</pubDate>
      <link>https://dev.to/kirodotdev/building-roblox-games-with-kiro-a-spec-driven-development-approach-3c8p</link>
      <guid>https://dev.to/kirodotdev/building-roblox-games-with-kiro-a-spec-driven-development-approach-3c8p</guid>
      <description>&lt;h2&gt;
  
  
  The Rise of Kiro and the Roblox Opportunity
&lt;/h2&gt;

&lt;p&gt;The developer community embraced Kiro with unprecedented enthusiasm. In just 3 days of its public preview launched on July 14, over 100,000 developers downloaded Kiro. That number has more than doubled in 90 days, showcasing the massive demand for AI-powered development tools with Agentic-IDE that actually understands how developers work.&lt;/p&gt;

&lt;p&gt;The best news? &lt;strong&gt;There's no more waitlist.&lt;/strong&gt; Anyone can now download Kiro and get started with 500 free bonus credits—that's equivalent to 50% of the Kiro Pro plan. It's the perfect opportunity to explore how AI can transform your development workflow.&lt;/p&gt;

&lt;p&gt;And speaking of opportunities, let's talk about Roblox.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Roblox Phenomenon
&lt;/h2&gt;

&lt;p&gt;As of mid-2025, Roblox has approximately &lt;strong&gt;111.8 million daily active users&lt;/strong&gt; and over 85.3 million in recent reports, with users spending billions of hours on the platform annually. The platform boasts over &lt;strong&gt;6.7 million user-created "experiences,"&lt;/strong&gt; and in 2024, developers earned over &lt;strong&gt;$701 million&lt;/strong&gt; from their creations.&lt;/p&gt;

&lt;p&gt;The user base is geographically diverse, with a growing older demographic alongside its traditional younger audience. This isn't just a gaming platform—it's a thriving economy where creators can turn their ideas into real income.&lt;/p&gt;

&lt;p&gt;But here's the challenge: building a professional-grade Roblox game requires juggling multiple systems, understanding Lua/Luau, managing complex project structures, and following best practices. That's where Kiro's spec-driven development approach changes everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Spec-Driven Development?
&lt;/h2&gt;

&lt;p&gt;Traditional AI assisted development with Vibe coding often goes like this: you have an idea, you start coding, you realize you forgot something, you refactor, you add features, things get messy, and before you know it, your codebase is a tangled mess.&lt;/p&gt;

&lt;p&gt;Spec-driven development flips this on its head. You start with a clear specification—a prompt to generate structured requirements document that defines what you want to build, how it should work, and what the end result should look like. Then, Kiro uses this spec to guide the entire development process, with design and tasks ensuring consistency, completeness, and quality from start to finish powered by its steering, agent hooks and MCP capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an Educational Math Game: A Real Example
&lt;/h2&gt;

&lt;p&gt;Let me show you how I used Kiro to build a complete Roblox educational math game—from concept to deployment—using spec-driven development. I talked about this game briefly in my &lt;a href="https://www.youtube.com/watch?v=a3nX_5mLlXc&amp;amp;t=989s" rel="noopener noreferrer"&gt;livestream with Darko on the Kiro bi-weekly show&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Initial Prompt
&lt;/h3&gt;

&lt;p&gt;Instead of diving straight into code, I started with a clear, structured prompt. Here's the template I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create an &amp;lt;educational math game&amp;gt; for Roblox that &amp;lt;teaches addition through 
engaging gameplay with progressive difficulty&amp;gt;. The project should be built 
using Rojo with Cargo for professional external development workflow, proper 
version control, and organized code structure.

Core Features:
- &amp;lt;Progressive difficulty system that adapts from simple (1-9) to complex 
  (up to 99) addition problems&amp;gt;
- &amp;lt;Multiple game modes: Classic, Blitz, Zen, Survival, Time Attack&amp;gt;
- &amp;lt;Power-up system with 5 power-ups: Time Freeze, Double Points, Skip, 
  Extra Time, Hint Mode&amp;gt;
- &amp;lt;Achievement system with 12+ achievements&amp;gt;
- &amp;lt;Enhanced scoring with speed bonus, streak multipliers, combo system&amp;gt;
- &amp;lt;Visual and audio effects: particle explosions, floating text, dynamic music&amp;gt;
- &amp;lt;Real-time leaderboards&amp;gt;
- &amp;lt;Data persistence for player stats and achievements&amp;gt;

Technical Requirements:
- Use Rojo for external development and live sync with Roblox Studio
- Organize code following Roblox service-based structure
- Implement &amp;lt;game logic, answer validation, data management&amp;gt; on server
- Implement &amp;lt;UI, visual effects, user input handling&amp;gt; on client
- Create SharedModules for &amp;lt;MathUtils, PowerUpManager, EffectsManager, 
  SoundManager, GameModeManager, ComboManager, RewardsManager, MascotManager&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One clear prompt with placeholders for the specific features I wanted.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Kiro Generated
&lt;/h3&gt;

&lt;p&gt;From this single prompt, Kiro created:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Complete Project Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;roblox-additive-game/
├── src/
│   ├── ReplicatedStorage/
│   │   ├── GameConfig.lua
│   │   └── SharedModules/
│   │       ├── MathUtils.lua
│   │       ├── PowerUpManager.lua
│   │       ├── EffectsManager.lua
│   │       ├── SoundManager.lua
│   │       ├── GameModeManager.lua
│   │       ├── ComboManager.lua
│   │       ├── RewardsManager.lua
│   │       └── MascotManager.lua
│   ├── ServerScriptService/
│   │   ├── GameManager.server.lua
│   │   └── PlayerDataManager.server.lua
│   ├── StarterGui/GameUI/
│   │   ├── MainMenu.lua
│   │   ├── GameScreen.lua
│   │   ├── GameModeSelector.lua
│   │   ├── PowerUpShop.lua
│   │   └── DailyRewardsUI.lua
│   └── StarterPlayerScripts/
│       └── ClientController.client.lua
├── build/
│   └── additive-game.rbxl
├── default.project.json
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Fully Functional Game Systems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All 5 game modes working with unique mechanics&lt;/li&gt;
&lt;li&gt;Complete power-up system with purchase and activation logic&lt;/li&gt;
&lt;li&gt;12 achievements with progress tracking&lt;/li&gt;
&lt;li&gt;Real-time scoring with multipliers and combos&lt;/li&gt;
&lt;li&gt;Visual effects using particle systems&lt;/li&gt;
&lt;li&gt;Dynamic audio system&lt;/li&gt;
&lt;li&gt;Data persistence using Roblox DataStores&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Professional Development Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rojo configuration for external development&lt;/li&gt;
&lt;li&gt;Live sync capability with &lt;code&gt;rojo serve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Build pipeline with &lt;code&gt;rojo build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Proper separation of client and server code&lt;/li&gt;
&lt;li&gt;Security-focused with server-side validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Comprehensive Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README with setup instructions&lt;/li&gt;
&lt;li&gt;Steering documents for best practices&lt;/li&gt;
&lt;li&gt;Code comments explaining complex logic&lt;/li&gt;
&lt;li&gt;Deployment guide&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Kiro Advantage: Steering Documents
&lt;/h3&gt;

&lt;p&gt;One of Kiro's most powerful features is steering documents. These are markdown files that automatically guide Kiro's code generation based on context.&lt;/p&gt;

&lt;p&gt;For this project, Kiro created:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tech.md&lt;/strong&gt; - Technology stack and build system guidelines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Platform: Roblox Studio &amp;amp; Roblox Engine
&lt;span class="p"&gt;-&lt;/span&gt; Language: Lua/Luau
&lt;span class="p"&gt;-&lt;/span&gt; Build System: Rojo
&lt;span class="p"&gt;-&lt;/span&gt; Common commands and architecture patterns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;structure.md&lt;/strong&gt; - Project organization rules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Root directory layout
&lt;span class="p"&gt;-&lt;/span&gt; Source code organization by Roblox services
&lt;span class="p"&gt;-&lt;/span&gt; Naming conventions
&lt;span class="p"&gt;-&lt;/span&gt; Module organization patterns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;product.md&lt;/strong&gt; - Product overview and features&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Core features and value propositions
&lt;span class="p"&gt;-&lt;/span&gt; Target audience
&lt;span class="p"&gt;-&lt;/span&gt; Key game mechanics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;lua-best-practices.md&lt;/strong&gt; - Lua/Luau coding standards&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Naming conventions
&lt;span class="p"&gt;-&lt;/span&gt; Performance best practices
&lt;span class="p"&gt;-&lt;/span&gt; Roblox-specific patterns
&lt;span class="p"&gt;-&lt;/span&gt; Error handling
&lt;span class="p"&gt;-&lt;/span&gt; Security considerations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These steering documents ensure that every piece of code Kiro generates follows the same standards, uses the same patterns, and maintains consistency throughout the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Development Experience
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Traditional Approach
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Set up Roblox Studio project&lt;/li&gt;
&lt;li&gt;Figure out Rojo configuration&lt;/li&gt;
&lt;li&gt;Create folder structure manually&lt;/li&gt;
&lt;li&gt;Write GameConfig.lua&lt;/li&gt;
&lt;li&gt;Implement MathUtils module&lt;/li&gt;
&lt;li&gt;Build game logic&lt;/li&gt;
&lt;li&gt;Create UI components&lt;/li&gt;
&lt;li&gt;Add visual effects&lt;/li&gt;
&lt;li&gt;Implement data persistence&lt;/li&gt;
&lt;li&gt;Debug and refactor&lt;/li&gt;
&lt;li&gt;Write documentation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Time estimate: 2-3 weeks for an experienced developer&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Kiro Spec-Driven Approach
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Write clear prompt with specifications&lt;/li&gt;
&lt;li&gt;Review generated code structure&lt;/li&gt;
&lt;li&gt;Test in Roblox Studio&lt;/li&gt;
&lt;li&gt;Iterate on specific features if needed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Time estimate: 2-3 hours&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Start with Clarity
&lt;/h3&gt;

&lt;p&gt;The better your initial prompt, the better the output. Use the template structure with clear placeholders for your specific features.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Leverage Steering Documents
&lt;/h3&gt;

&lt;p&gt;Let Kiro create steering documents that guide all future development. This ensures consistency even as you iterate.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Use Professional Tools
&lt;/h3&gt;

&lt;p&gt;Rojo + Kiro is a powerful combination. External development with version control beats working directly in Roblox Studio.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Focus on What Matters
&lt;/h3&gt;

&lt;p&gt;Instead of writing boilerplate and setting up infrastructure, spend your time on game design, balancing, and player experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Iterate Quickly
&lt;/h3&gt;

&lt;p&gt;With Kiro, you can test ideas rapidly. Don't like a game mode? Adjust the spec and regenerate. Want to add a new power-up? Update the prompt and let Kiro handle the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;The final game includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 5 fully functional game modes&lt;/li&gt;
&lt;li&gt;✅ 5 power-ups with purchase system&lt;/li&gt;
&lt;li&gt;✅ 12 achievements with tracking&lt;/li&gt;
&lt;li&gt;✅ Real-time leaderboards&lt;/li&gt;
&lt;li&gt;✅ Particle effects and animations&lt;/li&gt;
&lt;li&gt;✅ Dynamic audio system&lt;/li&gt;
&lt;li&gt;✅ Data persistence&lt;/li&gt;
&lt;li&gt;✅ Professional UI&lt;/li&gt;
&lt;li&gt;✅ Comprehensive documentation&lt;/li&gt;
&lt;li&gt;✅ Production-ready code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All from a single well-structured prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.roblox.com/games/77816883600785/Math-Game-built-by-Kiro" rel="noopener noreferrer"&gt;Play the game on Roblox →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduzz49o6yq8ukjfss0nd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduzz49o6yq8ukjfss0nd.png" alt="game" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Kiro for Roblox Development
&lt;/h2&gt;

&lt;p&gt;Ready to build your own Roblox game with Kiro? Here's how to get started:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Download Kiro
&lt;/h3&gt;

&lt;p&gt;Visit &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;kiro.dev&lt;/a&gt; and download the IDE. No waitlist, and you get 500 free credits to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Install Prerequisites
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Rust and Cargo&lt;/span&gt;
curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh

&lt;span class="c"&gt;# Install Rojo&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;rojo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install Roblox Studio
&lt;/h3&gt;

&lt;p&gt;Download from &lt;a href="https://www.roblox.com/create" rel="noopener noreferrer"&gt;roblox.com/create&lt;/a&gt; and install the Rojo plugin.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use the Template
&lt;/h3&gt;

&lt;p&gt;Copy the prompt template from this article, fill in your game idea, and let Kiro do the heavy lifting.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Iterate and Deploy
&lt;/h3&gt;

&lt;p&gt;Test in Studio, iterate on features, and publish to Roblox when ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Game Development
&lt;/h2&gt;

&lt;p&gt;With 111.8 million daily active users and $701 million paid to developers in 2024, Roblox represents a massive opportunity. But the barrier to entry has always been the technical complexity.&lt;/p&gt;

&lt;p&gt;Kiro's spec-driven development approach democratizes game creation. You don't need to be an expert in Lua, understand Roblox's service architecture, or know how to set up Rojo. You just need a clear idea and the ability to describe what you want to build.&lt;/p&gt;

&lt;p&gt;The 100,000+ developers who joined Kiro in the first 3 days understood this. They saw that AI-powered development isn't about replacing developers—it's about amplifying their creativity and removing the tedious parts of coding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;The template is ready. The tools are available. The platform has 111.8 million daily users waiting to play your game.&lt;/p&gt;

&lt;p&gt;What will you build?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Download Kiro&lt;/a&gt; - Get 500 free credits&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rojo.space/docs" rel="noopener noreferrer"&gt;Rojo Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://create.roblox.com/docs" rel="noopener noreferrer"&gt;Roblox Creator Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/roblox-additive-game" rel="noopener noreferrer"&gt;Example Project&lt;/a&gt; - Full source code&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Have you built something with Kiro? Share your experience in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kiro</category>
      <category>roblox</category>
      <category>ai</category>
      <category>rojo</category>
    </item>
    <item>
      <title>Taming Large Codebases with Kiro: Lessons from a 58K-LoC Rust Migration</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Tue, 23 Sep 2025 19:25:47 +0000</pubDate>
      <link>https://dev.to/kirodotdev/taming-large-codebases-with-kiro-lessons-from-a-58k-loc-rust-migration-36p9</link>
      <guid>https://dev.to/kirodotdev/taming-large-codebases-with-kiro-lessons-from-a-58k-loc-rust-migration-36p9</guid>
      <description>&lt;h2&gt;
  
  
  The Scale Problem
&lt;/h2&gt;

&lt;p&gt;AI assistants excel at small tasks but struggle with large codebase management. In the vibe mode, I asked Kiro to pick the largest open-source repo for testing Rust migration and Kiro shortlisted PostgreSQL repo containing 1.5M lines of C code. One advantage using Claude Sonnet 4 with Kiro was that the LLM's training data mostly included the PostgreSQL open-source repo, so it understood the codebase structure to some extent.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Tool Selection: Disabled 15+ tools, kept only:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;sequential-thinking - Complex problem breakdown&lt;/li&gt;
&lt;li&gt;git-repo-research - Easy access to source repo analysis&lt;/li&gt;
&lt;li&gt;aws-knowledge-mcp-server - AWS Documentation access&lt;/li&gt;
&lt;li&gt;aws-api-mcp-server - AWS Cloud integration
Although the 2 AWS MCP Servers could be disabled for this project, I keep them for other tasks, as they are my favourite ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anthropic's official sequential-thinking MCP server helped break down complex PostgreSQL migration specs into manageable steps through dynamic and reflective problem-solving. It enables iterative thought refinement, allowing revision of &lt;br&gt;
previous reasoning and branching into alternative approaches, which helped Kiro systematically work through dependencies and edge cases with adaptive thinking rather than linear progression.&lt;/p&gt;

&lt;p&gt;AWS Labs git-repo-research - The search_repos_on_github and access_file tools provided access to postgres repository and codebase, enabling discovery and analysis design patterns and implementation strategies.&lt;/p&gt;

&lt;p&gt;After multiple iterations of specs and using my 3 Kiro accounts (kiro hackathon google account, AWS Builder ID account and AWS IAM Identity Center account), I got a working postgres server and a psql client built in Rust with core UPSERT functionality. Here are the generated code stats: 58,478 lines Rust code, 167 files, 264 total files.&lt;/p&gt;
&lt;h3&gt;
  
  
  Top 3 Steering Guides Used with Spec-driven development approach:
&lt;/h3&gt;

&lt;p&gt;• Visibility: Making failing tests visible to Kiro&lt;br&gt;
• Organization: Preventing LLM codebase chaos&lt;br&gt;
• Efficiency: Avoiding duplication and waste&lt;/p&gt;
&lt;h3&gt;
  
  
  Guide 1: Visibility - "If Kiro Can't See It, It Didn't Happen"
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Critical for shell integration issues
cargo test 2&amp;gt;&amp;amp;1 | tee compilation_errors.log
cargo build --workspace 2&amp;gt;&amp;amp;1 | tee build_errors.log
cargo clippy --workspace 2&amp;gt;&amp;amp;1 | tee lint_errors.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Problem: Shell integration failures caused Kiro to assume command success when tests actually fail.&lt;/p&gt;

&lt;p&gt;Technical Solution: &lt;br&gt;
• 2&amp;gt;&amp;amp;1 redirects stderr to stdout&lt;br&gt;
• tee writes to both file and terminal&lt;br&gt;
• Always clean up: rm *.log after verification&lt;/p&gt;

&lt;p&gt;Real Impact: Prevented LLM loops debugging phantom "passing" tests that were actually compilation failures.&lt;/p&gt;

&lt;p&gt;Side Benefit: As a pro tip, when my Kiro free tier limits were running out of one account, and the tests were actually reporting success due to my shell integration issue, I used the Q Developer Extension in Kiro IDE itself to fix the failing tests and saved on my Kiro credits usage. I also upgraded my AWS Builder ID account to a Kiro pro account and later also got benefit of free August credits, and also the extra limits that were reset for everyone in August/September months. &lt;/p&gt;
&lt;h3&gt;
  
  
  Guide 2: Organization - "Every File Has a Home"
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgres-rust-migration/
├── docs/{spec-name}/                    # Implementation summaries
│   └── insert-storage-persistence_8_summary.md
├── scripts/verification/{spec-name}/    # Verification scripts
│   └── database-durability_verification.rs
├── crates/{crate}/tests/temp/          # Temporary test files
│   └── temp_sql-update_integration_test.rs
└── target/                             # Build artifacts gitignored
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Critical Rules:&lt;br&gt;
• &lt;strong&gt;Never create files in project root&lt;/strong&gt; - causes workspace pollution&lt;br&gt;
• &lt;strong&gt;Spec-name prefixes&lt;/strong&gt; for all artifacts: {spec-name}&lt;em&gt;{task-number}&lt;/em&gt;{type}&lt;br&gt;
• &lt;strong&gt;Immediate cleanup&lt;/strong&gt; of temp files and logs&lt;br&gt;
• &lt;strong&gt;Use tempfile crate&lt;/strong&gt; for truly temporary files&lt;/p&gt;
&lt;h3&gt;
  
  
  Guide 3: Efficiency - "Search Before You Code"
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Before implementing any function
rg "fn.*storage.*persist" --type rust
rg "struct.*Buffer" --type rust  
rg "impl.*Transaction" --type rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Code Duplication Prevention:&lt;br&gt;
• Search entire codebase before implementing&lt;br&gt;
• Check similar filenames: find . -name "&lt;em&gt;storage&lt;/em&gt;" -name "*.rs"&lt;br&gt;
• Verify existing functionality in related crates&lt;/p&gt;

&lt;p&gt;Rust-Specific Rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Always use cargo, never rustc directly
cargo build --workspace    # ✓ Handles dependencies
rustc src/main.rs          # ✗ Fails in multi-crate workspace

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Testing workflow
cargo test --workspace                    # All tests
cargo test --package postgres-storage     # Specific crate
cargo run --example verification_script   # Examples

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repository Hygiene:&lt;br&gt;
.gitignore&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/target/
*.log
.env
*_temp*
*_backup*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Hooks: Automation
&lt;/h3&gt;

&lt;p&gt;Tokei Integration (auto-updates README):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Post-task hook
tokei --output json 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instructions for Kiro agent: A task completion document has been updated. Please run &lt;code&gt;tokei . --output json&lt;/code&gt; to get the current lines of code statistics, then update the README.md file with the latest code metrics. Include total lines of code, lines by language (especially Rust), and any other relevant statistics from the tokei output. Make sure to update any existing code statistics section or add a new one if it doesn't exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Kiro Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you move the Kiro project directory, and restart Kiro from different location, then you loose the chat and spec sessions history, so its always recommended to save the session history using task summary as mentioned in the steering rule above&lt;/li&gt;
&lt;li&gt;Always ask Kiro to run cargo commands from workspace root to avoid duplicate target directories, e.g.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd $HOME/project &amp;amp;&amp;amp; cargo build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Have Kiro run tests with the lowest verbosity and to filter with grep if necessary to avoid context filling up quickly due to large outputs&lt;/li&gt;
&lt;li&gt;When Kiro runs an AWS CLI command, have it include &lt;code&gt;--no-cli-pager&lt;/code&gt;. This prevents interactive pager output that the agent can't see or exit from. Other similar commands that generate huge outputs quickly fill the session context, so use similar technique to skip this output in the response if it is not useful for the agent.&lt;/li&gt;
&lt;li&gt;When multiple approaches exist for tasks like publishing to Amplify, ask Kiro to create standardized script and instruct to always use that script rather than improvising different methods each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing the Postgres-Rust
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Start the postgres server
./target/release/postgres-server --config postgresql.conf &amp;gt; server.log 2&amp;gt;&amp;amp;1 &amp;amp;

# 1. Create table
./target/release/psql -c "CREATE TABLE kiro (id INTEGER, name TEXT, age INTEGER, email TEXT);"

# 2. Insert records
./target/release/psql -c "INSERT INTO kiro (id, name, age, email) VALUES (1, 'Alice Johnson', 28, 'alice@example.com');"
./target/release/psql -c "INSERT INTO kiro (id, name, age, email) VALUES (2, 'Bob Smith', 35, 'bob@example.com');"

# 3. Select to verify
./target/release/psql -c "SELECT * FROM kiro;"

# 4. Update Alice's record
./target/release/psql -c "UPDATE kiro SET age = 29, email = 'alice.updated@example.com' WHERE id = 1;"

# 5. Select to verify update
./target/release/psql -c "SELECT * FROM kiro;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Postgres client psql with update statements work!&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwuaem3cmzbelqj9w8wa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwuaem3cmzbelqj9w8wa9.png" alt="kiro results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restarting Postgres server to verify persistent updates&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv82wbnrgbnpabbtla0sz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv82wbnrgbnpabbtla0sz.png" alt="restarting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out my &lt;a href="https://github.com/awsdataarchitect/postgres-rust-migration" rel="noopener noreferrer"&gt;postgres-rust-migration&lt;/a&gt; repository for the complete implementation with 58K+ lines of Rust code across modular crates.&lt;/p&gt;
&lt;h2&gt;
  
  
  Watch the livestream recording | Kiro bi-weekly show | An engineer's take on Kiro
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/a3nX_5mLlXc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Results: Measurable Impact (AI - calculated numbers)
&lt;/h3&gt;

&lt;p&gt;• &lt;strong&gt;Project size&lt;/strong&gt;: Reduced repo size by excluding targets&lt;br&gt;
• &lt;strong&gt;Build time&lt;/strong&gt;: 15% faster with proper workspace structure&lt;br&gt;
• &lt;strong&gt;Debug efficiency&lt;/strong&gt;: 80% reduction in false-positive "passing" tests&lt;br&gt;
• &lt;strong&gt;Code reuse&lt;/strong&gt;: 23% of functions found existing implementations before coding&lt;/p&gt;

</description>
      <category>kiro</category>
      <category>softwaredevelopment</category>
      <category>coding</category>
      <category>agentic</category>
    </item>
    <item>
      <title>RAG-based Presentation Generator built with Kiro</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Mon, 15 Sep 2025 18:25:58 +0000</pubDate>
      <link>https://dev.to/kirodotdev/rag-based-presentation-generator-built-with-kiro-j9o</link>
      <guid>https://dev.to/kirodotdev/rag-based-presentation-generator-built-with-kiro-j9o</guid>
      <description>&lt;p&gt;&lt;em&gt;How a presentation emergency inspired a new approach to AI-powered development&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Crisis That Started Everything
&lt;/h2&gt;

&lt;p&gt;Picture this: 15 minutes before a major presentation, your file is corrupted. Hundreds of developers are waiting. Most would panic.&lt;/p&gt;

&lt;p&gt;However, Donnie Prakoso, Principal Developer Advocate at AWS, &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7338386803713810432/" rel="noopener noreferrer"&gt;turned to Amazon Q CLI&lt;/a&gt;. His methodical approach - requirements, task-based workflows, MCP tools - saved the day. But his key insight changed everything: "It's not about the AI tool itself, but how you integrate it into your workflow."&lt;/p&gt;

&lt;p&gt;This real life scenario inspired me with the idea to build a full self-service serverless AI app, a Retrieval-Augmented Generation (RAG) - based Presentation Generator by using Kiro and leveraging these key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serverless AWS architecture with Bedrock Models&lt;/li&gt;
&lt;li&gt;Real-time document processing with Bedrock Knowledge Base
&lt;/li&gt;
&lt;li&gt;Per-user data isolation for enterprise security&lt;/li&gt;
&lt;li&gt;S3 Vectors integration (no Amazon OpenSearch Serverless) for cost-optimized storage &lt;/li&gt;
&lt;li&gt;React frontend with modern Amplify v6 authentication&lt;/li&gt;
&lt;li&gt;CDK infrastructure scaling from prototype to production&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Kiro Transformation
&lt;/h2&gt;

&lt;p&gt;Remembering the workflow-first approach, I opened Kiro: "Help me build an AI-based Presentation Generator system with above key capabilities that can help with edit slides, geneate content, export the presentation to Marp, Reveal.js or HTML formats"&lt;/p&gt;

&lt;p&gt;What happened next was unlike any coding experience I'd had.&lt;/p&gt;

&lt;p&gt;Kiro didn't give generic answers. It broke down complexity into manageable tasks, analyzed my specific architecture needs with an accurate design, and hooked me to &lt;strong&gt;spec-driven development&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spec-Driven Revolution
&lt;/h2&gt;

&lt;p&gt;Instead of one massive requirements document, over the development cycle, I created 5 different modular specs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator/tree/main/.kiro/specs/aws-native-rag" rel="noopener noreferrer"&gt;&lt;strong&gt;AWS-Native RAG spec&lt;/strong&gt;&lt;/a&gt;: Core system with Bedrock and S3 Vectors&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator/tree/main/.kiro/specs/system-fixes" rel="noopener noreferrer"&gt;&lt;strong&gt;System Fixes spec&lt;/strong&gt;&lt;/a&gt;: Surgical improvements without breaking production&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator/tree/main/.kiro/specs/ui-professional-enhancement" rel="noopener noreferrer"&gt;&lt;strong&gt;UI Enhancement spec&lt;/strong&gt;&lt;/a&gt;: Professional interface without backend risk
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator/tree/main/.kiro/specs/developer-blog-platform" rel="noopener noreferrer"&gt;&lt;strong&gt;Blog Platform spec&lt;/strong&gt;&lt;/a&gt;: Content creation system (generating this post)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator/tree/main/.kiro/specs/security-vulnerability-assessment" rel="noopener noreferrer"&gt;&lt;strong&gt;Security Vulnerability Assessment specs&lt;/strong&gt;&lt;/a&gt;: Full assessment of the system for any vulnerabilities to make sure the app is secure and production ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each spec operated independently. I could iterate fearlessly on complex use-cases separately and one-after-other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Production AI: The Technical Journey
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bkiss1vaqmuq41lm9qn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bkiss1vaqmuq41lm9qn.png" alt="UI" width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28opkyyucp083knkil32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28opkyyucp083knkil32.png" alt="Improve slides with AI" width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The S3 Vectors Breakthrough
&lt;/h3&gt;

&lt;p&gt;When I mentioned vector storage costs, Kiro's MCP integration with my configured awslabs aws-knowledge-mcp-server immediately suggested S3 Vectors - a preview service yet fully searchable with the MCP server containing access to all examples and ready to use code from AWS blog posts and official AWS documentation:&lt;/p&gt;

&lt;p&gt;"S3 Vectors can reduce costs by 90% compared to OpenSearch Serverless."&lt;/p&gt;

&lt;p&gt;The implementation was game-changing. For instance, this single line saved hours of debugging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;s3vectors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;vectorBucketName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;indexName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dimension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;distanceMetric&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cosine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dataType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;float32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;metadataConfiguration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nonFilterableMetadataKeys&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AMAZON_BEDROCK_TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# CRITICAL
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result: 90% cost reduction while maintaining full functionality.&lt;/p&gt;

&lt;p&gt;I asked Kiro about CDK's current lack of native support for S3 Vectors (which would require implementing a Custom Lambda Resource), and we ended up with the optimal architectural decision  to handle vector index creation programmatically at runtime using the boto3 SDK during document ingestion, ensuring future compatibility and per-user isolation.&lt;/p&gt;

&lt;p&gt;Kiro's test-driven development approach was revolutionary - it iterates on generated tests until they pass and the code achieves full functionality. By structuring specifications in repeatable, "declarative format", Kiro essentially functions as a specifications "compiler", transforming human-readable requirements directly into working code. This paradigm shift turns Kiro into an intelligent coding agent that bridges the gap between architectural intent and executable implementation, making spec-to-code transformation as reliable as traditional compilation processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  System Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1tkyojadtb6hfsfz9oq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1tkyojadtb6hfsfz9oq.png" alt="Architecture" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-User Architecture Innovation
&lt;/h3&gt;

&lt;p&gt;Kiro proposed something I hadn't considered - per-user Knowledge Bases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traditional: Shared KB → Complex filtering → Performance issues
Innovation: User A → KB A, User B → KB B → Perfect isolation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This architecture eliminated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex metadata filtering&lt;/li&gt;
&lt;li&gt;S3 Vectors 2KB metadata limits
&lt;/li&gt;
&lt;li&gt;Cross-user data contamination&lt;/li&gt;
&lt;li&gt;Query performance bottlenecks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Complete CDK Infrastructure Generation
&lt;/h3&gt;

&lt;p&gt;Instead of generic boilerplate, Kiro generated production-ready infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generated by Kiro - Complete serverless stack&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeBaseRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;KnowledgeBaseRole&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;assumedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bedrock.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;inlinePolicies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;S3VectorsPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PolicyDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3vectors:CreateVectorBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3vectors:GetIndex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Often missed, critical for debugging&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3vectors:QueryVectors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code (thanks to the awslabs mcp server) included the often-missed &lt;code&gt;s3vectors:GetIndex&lt;/code&gt; permission that would have taken hours to debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sophisticated Lambda Functions
&lt;/h3&gt;

&lt;p&gt;Kiro generated complete backend Lambda Function code with proper error handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BedrockRAGService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_similar_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;user_kb_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_user_kb_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user_kb_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No Knowledge Base found for user &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bedrock_agent_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;knowledgeBaseId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_kb_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;knowledge_base_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;retrievalQuery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="n"&gt;retrievalConfiguration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vectorSearchConfiguration&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;numberOfResults&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_format_search_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RAG search failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Search temporarily unavailable&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code included timeout handling, user-specific routing, and graceful error recovery - patterns that would have taken days to implement properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Production Architecture
&lt;/h2&gt;

&lt;p&gt;The application runs on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Next.js 15.4.5 + React 19.1.0, AWS Amplify v6, Webpack 5 (~170 KiB bundle)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Python 3.11 Lambda functions with Bedrock Knowledge Base integration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Services&lt;/strong&gt;: Amazon Nova Pro + Titan embeddings, S3 Vectors storage&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Layer&lt;/strong&gt;: DynamoDB + S3 with per-user isolation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt;: 90% reduction in vector storage costs vs traditional approaches&lt;/p&gt;

&lt;h2&gt;
  
  
  The Velocity Impact
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional Approach (Estimated):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature planning: 2-3 weeks&lt;/li&gt;
&lt;li&gt;Cross-system coordination: 1-2 weeks&lt;/li&gt;
&lt;li&gt;Implementation with risk mitigation: 4-6 weeks
&lt;/li&gt;
&lt;li&gt;Testing and validation: 2-3 weeks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total: 9-14 weeks per feature&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Spec-Driven Approach (Actual):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focused spec creation: 2-3 days&lt;/li&gt;
&lt;li&gt;Independent implementation: 1-2 days&lt;/li&gt;
&lt;li&gt;Isolated testing: 3-5 days&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total: 1-2 weeks&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beyond Code Generation
&lt;/h2&gt;

&lt;p&gt;Kiro understood broader context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Experience&lt;/strong&gt;: Suggested async processing to avoid wait times&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Optimization&lt;/strong&gt;: Recommended S3 Vectors for 90% savings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Implemented per-user isolation without being asked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Designed for 100 users per AWS account with clear scaling paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Automation Revolution
&lt;/h2&gt;

&lt;p&gt;Kiro helped create agent hooks that eliminated entire bug categories:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CDK Synth Hook&lt;/strong&gt;: Automatically validates infrastructure changes&lt;br&gt;
&lt;strong&gt;README Spell Check&lt;/strong&gt;: Maintains documentation quality&lt;br&gt;
&lt;strong&gt;Test Automation&lt;/strong&gt;: Runs comprehensive validation on every change&lt;/p&gt;

&lt;p&gt;These hooks transformed development from reactive debugging to proactive quality assurance.&lt;/p&gt;

&lt;p&gt;I heavily used my Kiro &lt;a href="https://dev.to/kirodotdev/accelerating-ai-development-workflows-the-kiro-best-practices-boilerplate-4h6o"&gt;steering files&lt;/a&gt; that helped to maintain best practices all throughout the development cycle. Occasionally, I asked Kiro to automatically refine my steering files with the codebase, so it does not go off-track whenever implementing a new spec (I had total 5 specs for this project)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compound Effect
&lt;/h2&gt;

&lt;p&gt;Spec-driven development changed how I approach complex systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;: "How can I add this feature without breaking anything?"&lt;br&gt;
&lt;strong&gt;After&lt;/strong&gt;: "What focused spec addresses this specific concern?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;: "This change might affect multiple systems."&lt;br&gt;
&lt;strong&gt;After&lt;/strong&gt;: "This spec targets exactly one area."&lt;/p&gt;

&lt;p&gt;The spec-driven development eliminated the fear of changing complex production systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Milestone 1&lt;/strong&gt;: AWS-Native RAG spec → Production deployment with S3 Vectors&lt;br&gt;
&lt;strong&gt;Milestone 2&lt;/strong&gt;: System Fixes spec → Critical issues resolved without disruption&lt;br&gt;
&lt;strong&gt;Milestone 3&lt;/strong&gt;: UI Enhancement spec → Professional interface without backend changes&lt;br&gt;
&lt;strong&gt;Milestone 4&lt;/strong&gt;: Blog Platform spec → Content creation system for sharing this story&lt;br&gt;
&lt;strong&gt;Milestone 5&lt;/strong&gt;: Security Assessment spec → Full vulnerability assessment of the system&lt;/p&gt;

&lt;p&gt;Each spec operated independently, allowing rapid iteration without fear of breaking existing functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of AI Development
&lt;/h2&gt;

&lt;p&gt;This approach scales beyond the RAG-based Presentation Generator:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise Applications&lt;/strong&gt;: Core business logic, UI enhancement, performance optimization as separate specs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microservices&lt;/strong&gt;: Service foundation, API enhancement, monitoring as isolated concerns&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Systems&lt;/strong&gt;: Model integration, data processing, user interface as modular specifications&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Workflow-first thinking&lt;/strong&gt; beats tool-first approaches&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spec-driven development&lt;/strong&gt; enables fearless iteration on complex systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI assistants excel&lt;/strong&gt; at architectural guidance within structured processes
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular specs prevent&lt;/strong&gt; technical debt accumulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-user architectures&lt;/strong&gt; solve isolation and scaling challenges elegantly&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The complete code is available at &lt;a href="https://github.com/awsdataarchitect/ai-ppt-generator" rel="noopener noreferrer"&gt;github.com/awsdataarchitect/ai-ppt-generator&lt;/a&gt; with detailed instructions for reproducing this spec-driven development approach.&lt;/p&gt;

&lt;p&gt;The live AI PPT Generator showcases these techniques in production: &lt;a href="https://main.d2ashs0ytllqag.amplifyapp.com" rel="noopener noreferrer"&gt;https://main.d2ashs0ytllqag.amplifyapp.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Experience how workflow-first AI development transforms complex AWS projects from chaotic research cycles into predictable, scalable methodologies.&lt;/p&gt;

&lt;p&gt;The future of software development isn't about AI replacing developers - it's about integrating AI into workflows that amplify human creativity and eliminate the fear of building complex systems.&lt;/p&gt;

</description>
      <category>kiro</category>
      <category>s3vectors</category>
      <category>rag</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>Building an AI Dining Assistant in 30 Minutes: From Local Development to Cloud Deployment</title>
      <dc:creator>Vivek V.</dc:creator>
      <pubDate>Fri, 05 Sep 2025 19:27:42 +0000</pubDate>
      <link>https://dev.to/aws-builders/building-an-ai-dining-assistant-in-30-minutes-from-local-development-to-cloud-deployment-499l</link>
      <guid>https://dev.to/aws-builders/building-an-ai-dining-assistant-in-30-minutes-from-local-development-to-cloud-deployment-499l</guid>
      <description>&lt;p&gt;&lt;em&gt;How I built a restaurant discovery and dining plan generator AI Agent using Amazon Bedrock AgentCore, and why it's easier than you think.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea: AI Agent for Dining
&lt;/h2&gt;

&lt;p&gt;You've just landed in Seattle for a business trip. It's 7 PM, you're hungry, and you have no idea where to eat. You want something authentic, not touristy, with good reviews, and ideally within walking distance of your hotel. &lt;/p&gt;

&lt;p&gt;That's when I decided to build my own AI dining assistant that could not only find restaurants but create complete dining plans with recommendations, party size considerations, and local insights. &lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built: The Bedrock AgentCore Dining Agent
&lt;/h2&gt;

&lt;p&gt;The agent I created does three things exceptionally well:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Smart Restaurant Discovery&lt;/strong&gt;: Uses real-time web search to find restaurants based on location, cuisine, or specific requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent Menu Analysis&lt;/strong&gt;: Automatically scrapes restaurant websites to understand their offerings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalized Dining Plans&lt;/strong&gt;: Creates detailed recommendations including party size, budget estimates, and local tips/taxes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But here's the kicker - it took me less than 30 minutes to build and deploy, thanks to Kiro for building the frontend code in React and the backend AgentCore agent using Strands Agent framework (app.py) and deploying it on the Amazon Bedrock AgentCore Runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic Behind the Scenes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Real Data, Real Results
&lt;/h3&gt;

&lt;p&gt;Unlike other AI assistants that give you generic responses, and incomplete web searches, my agent uses &lt;strong&gt;BrightData's MCP integration&lt;/strong&gt; to perform actual web searches and scrape real restaurant data. When you ask for "Italian restaurants in Seattle" you get current, accurate results with real ratings, addresses, and phone numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Five AI Models, One Interface
&lt;/h3&gt;

&lt;p&gt;The agent supports five different Bedrock models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nova Premier&lt;/strong&gt; (my go-to for complex queries)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nova Micro&lt;/strong&gt; (lightning-fast for simple searches)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Sonnet 4&lt;/strong&gt; (excellent for creative dining plans)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Opus 4.1&lt;/strong&gt; (the most sophisticated reasoning)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPT-OSS 120B&lt;/strong&gt; (OpenAI's GPT open-weight Model that works really well with Bedrock and runs fast)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can switch between models dynamically based on my preference - fast results or deep analysis. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You might need to enable Bedrock model access for Amazon Nova and Anthropic Claude models. The OpenAI's GPT-OSS models are enabled automatically in Bedrock, eliminating the friction between dev teams, however, these GPT-OSS Bedrock model are only available in the us-west-2 (Oregon) region at the time of publishing this blog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intelligent Tool Routing
&lt;/h3&gt;

&lt;p&gt;The agent automatically decides which tools to use based on your request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Find restaurants"&lt;/strong&gt; → Triggers web search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Dining plan at Wild Ginger for 2"&lt;/strong&gt; → Searches for the Wild Ginger restaurant, finds their website, scrapes the menu, and creates a personalized plan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Best sushi in Seattle"&lt;/strong&gt; → Combines search with local insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Development Journey: Surprisingly Simple
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: The Foundation (5 minutes)
&lt;/h3&gt;

&lt;p&gt;I started with Amazon Bedrock AgentCore and the Strands Agent framework. The setup was straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us.amazon.nova-premier-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scrape_as_markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_dining_plan&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: MCP Integration (10 minutes)
&lt;/h3&gt;

&lt;p&gt;The real power came from integrating BrightData's MCP (Model Context Protocol) server. This gave my agent access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CAPTCHA-protected Google search&lt;/li&gt;
&lt;li&gt;Professional web scraping capabilities&lt;/li&gt;
&lt;li&gt;Real-time data extraction
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; api_token = os.getenv('BRIGHTDATA_API_TOKEN')
        if not api_token:
            raise ValueError("BRIGHTDATA_API_TOKEN environment variable not set")

        mcp_url = f"https://mcp.brightdata.com/sse?token={api_token}"

        async with sse_client(mcp_url) as (read_stream, write_stream):
            async with ClientSession(read_stream, write_stream) as session:
                await session.initialize()

                result = await session.call_tool(tool_name, arguments)
                return str(result.content[0].text) if result.content else "No result"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more mock data or limited APIs - this agent works with the real web.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: React Frontend (15 minutes)
&lt;/h3&gt;

&lt;p&gt;I built a clean React frontend with Kiro prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model selection dropdown&lt;/li&gt;
&lt;li&gt;Local vs cloud endpoint switching&lt;/li&gt;
&lt;li&gt;Real-time response streaming&lt;/li&gt;
&lt;li&gt;Mobile-responsive design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire frontend took just 15 minutes because I focused on functionality over fancy animations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;: As a best practice, I recommend to use a separate frontend layer for the agent, and keep the Agent Business Logic separate in AgentCore, although you can still use AgentCore local itself as an UI option without needing a separate frontend layer. So in essence, you can use any of these options to host your frontend - a localhost frontend or cloud hosted single page app (S3, CloudFront, Amplify), Lambda, ECS, EKS, or AgentCore. &lt;br&gt;
For my frontend, I used the React based localhost UI for this quick demo. &lt;/p&gt;

&lt;p&gt;For my backend, I provided an option in UI (screenshot in next section) for switching between a local AgentCore backend and the AWS Cloud AgentCore Runtime backend just to demo both possibilities for a AgentCore backend.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Testing: The "Toronto Test"
&lt;/h2&gt;

&lt;p&gt;To test the agent, I asked it: &lt;em&gt;"I'm visiting Toronto with 3 friends. Create a dining plan at Canoe in downtown core"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's what happened:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Search Phase&lt;/strong&gt;: The agent found Canoe restaurant in Toronto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menu Discovery&lt;/strong&gt;: Found Canoe's website and scraped their current menu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan Creation&lt;/strong&gt;: Generated a complete dining plan including:

&lt;ul&gt;
&lt;li&gt;Recommended dishes for sharing&lt;/li&gt;
&lt;li&gt;Wine pairings&lt;/li&gt;
&lt;li&gt;Budget estimate (~$322 CAD for 4 people)&lt;/li&gt;
&lt;li&gt;Reservation tips&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total response time: 50 seconds. Quality: Better than a human concierge or other AI conversation agent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ync6hw0d2li7fw58we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ync6hw0d2li7fw58we.png" alt="Local UI" width="800" height="797"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deployment: From Local to Cloud in One Command
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Local Development (for frontend in React and backend dining agent in AgentCore local)
&lt;/h3&gt;

&lt;p&gt;Running locally is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python app.py &amp;amp;
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm start &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two commands, and you have a full-stack AI dining assistant running on your laptop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Deployment (for backend dining agent in AgentCore Runtime)
&lt;/h3&gt;

&lt;p&gt;Here's where AgentCore really shines. Deploying backend to AWS AgentCore Runtime took literally one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentcore launch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No Docker files, no Kubernetes manifests, no infrastructure headaches. Following simple prompts with agentcore CLI, AgentCore handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container building via CodeBuild&lt;/li&gt;
&lt;li&gt;ECR repository creation&lt;/li&gt;
&lt;li&gt;IAM role configuration&lt;/li&gt;
&lt;li&gt;Runtime deployment&lt;/li&gt;
&lt;li&gt;Auto-scaling setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test the deployed Cloud AgentCore runtime with my local frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cloud_proxy.py &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts a proxy server on port 8081 that connects my local frontend to the deployed AgentCore runtime, enabling seamless local-to-cloud testing.&lt;/p&gt;

&lt;p&gt;In 15 minutes, I had a production-ready AI agent running in the cloud with enterprise-grade reliability.&lt;/p&gt;

&lt;p&gt;Screenshot of Agent sandbox in AgentCore Console to test the AgentCore Runtime Hosted Endpoint:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20flgpbp8p7rt87a130j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20flgpbp8p7rt87a130j.png" alt="agentcore sandbox" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Secret Sauce: Environment Variables Done Right
&lt;/h2&gt;

&lt;p&gt;One critical lesson I learned: AgentCore has two configuration layers. The YAML file handles deployment settings, but runtime environment variables (like an API token) require a separate step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock-agentcore-control update-agent-runtime &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-runtime-id&lt;/span&gt; YOUR_AGENT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--environment-variables&lt;/span&gt; &lt;span class="s1"&gt;'BRIGHTDATA_API_TOKEN=your_token'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation ensures security and flexibility in production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Beyond Just Restaurants
&lt;/h2&gt;

&lt;p&gt;While I built this for restaurant discovery, the architecture demonstrates something bigger. This is how AI agents should work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real data integration with MCP Tools&lt;/strong&gt; (not hallucinated responses)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple model support&lt;/strong&gt; (choose the right tool for the job)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless deployment&lt;/strong&gt; (from laptop to cloud in minutes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production-ready security&lt;/strong&gt; (proper environment variable handling)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same pattern works for travel planning, event coordination, research assistance, or any domain where you need AI to interact with real-world data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bedrock AgentCore Wins
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2-3 days for infrastructure setup&lt;/li&gt;
&lt;li&gt;Multiple services to manage (API Gateway, Lambda, ECS, etc.)&lt;/li&gt;
&lt;li&gt;Complex deployment and orchestration pipelines&lt;/li&gt;
&lt;li&gt;Ongoing maintenance overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AgentCore Agentic AI Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;30 minutes total development time&lt;/li&gt;
&lt;li&gt;One command deployment&lt;/li&gt;
&lt;li&gt;Zero infrastructure management&lt;/li&gt;
&lt;li&gt;Built-in scaling and monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The productivity difference is the key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The complete code is available, and you can have your own dining agent running in minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone the repository&lt;/strong&gt; &lt;a href="https://github.com/awsdataarchitect/bedrock-dining-agent" rel="noopener noreferrer"&gt;https://github.com/awsdataarchitect/bedrock-dining-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add your BrightData API token&lt;/strong&gt; (free tier available, I used promo code devto1 for $250 credits) &lt;a href="https://brightdata.com" rel="noopener noreferrer"&gt;https://brightdata.com&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run locally&lt;/strong&gt;: &lt;code&gt;python app.py &amp;amp; &amp;amp;&amp;amp; cd frontend &amp;amp;&amp;amp; npm start &amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy to cloud&lt;/strong&gt;: &lt;code&gt;agentcore launch&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. You now have a production-ready AI dining assistant.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This project opened my eyes to the potential of Bedrock AgentCore for rapid Agentic AI application development with seamless integration of ANY model supported by Bedrock (e.g. Claude, Nova, GPT-OSS) and ANY Agent framework (I used Strands Agents SDK), real-time data access through MCP tools, and effortless cloud deployment capabilities. &lt;/p&gt;

&lt;p&gt;Next, I'm planning to enhance this agent with new features by using Kiro:&lt;br&gt;
&lt;strong&gt;Reservation Agent&lt;/strong&gt;: Automated table booking through Amazon Connect integration that calls restaurants directly to secure reservations based on your preferred time and group size.&lt;br&gt;
&lt;strong&gt;AgentCore Memory&lt;/strong&gt;: Enabling long term/short term memory that can remember past interactions and use them to create a personalized dining plan for the next time.&lt;/p&gt;

&lt;p&gt;The pattern is the same: real data integration + multiple AI models + one-command deployment = powerful applications in minutes, not months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building sophisticated AI agents used to require teams of engineers and months of development. With Amazon Bedrock AgentCore, I built and deployed a production-ready dining assistant in 30 minutes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ready to build your own AI agent? The dining assistant is just the beginning.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try the Bedrock Dining Agent&lt;/strong&gt;: &lt;a href="https://github.com/awsdataarchitect/bedrock-dining-agent" rel="noopener noreferrer"&gt;https://github.com/awsdataarchitect/bedrock-dining-agent&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Deploy in 30 minutes&lt;/strong&gt;: Follow the README quick start guide&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Questions?&lt;/strong&gt; Reach out - I'd love to see what you build next. As Werner says, now go build!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>kiro</category>
      <category>agentcore</category>
      <category>strandsagent</category>
    </item>
  </channel>
</rss>
