<?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: Lewis Sawe</title>
    <description>The latest articles on DEV Community by Lewis Sawe (@lewisawe).</description>
    <link>https://dev.to/lewisawe</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%2F1061372%2F66521ce2-043c-4326-a061-54645ed0f31c.png</url>
      <title>DEV Community: Lewis Sawe</title>
      <link>https://dev.to/lewisawe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lewisawe"/>
    <language>en</language>
    <item>
      <title>Building a Project Risk Engine on Top of Notion MCP</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 29 Mar 2026 22:21:31 +0000</pubDate>
      <link>https://dev.to/lewisawe/building-a-project-risk-engine-on-top-of-notion-mcp-2fak</link>
      <guid>https://dev.to/lewisawe/building-a-project-risk-engine-on-top-of-notion-mcp-2fak</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;Risk Radar reads your Notion project databases, builds a dependency graph in memory, and writes risk reports back to Notion. It finds critical paths, single points of failure, and cascade risks that project managers usually track in their heads (or don't track at all).&lt;/p&gt;

&lt;p&gt;The part I'm most proud of: when a task is overdue, the agent walks the dependency graph and pushes every downstream deadline forward through &lt;code&gt;notion-update-page&lt;/code&gt;. Mark one task late, run the scan, and watch 8 dates shift in Notion automatically.&lt;/p&gt;

&lt;p&gt;Everything goes through Notion's MCP server. No direct API calls. Notion is the entire data layer.&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&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/lewisawe" rel="noopener noreferrer"&gt;
        lewisawe
      &lt;/a&gt; / &lt;a href="https://github.com/lewisawe/risk-radar" rel="noopener noreferrer"&gt;
        risk-radar
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;🎯 Risk Radar — Dependency &amp;amp; Risk Intelligence for Notion&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Built for the Notion MCP Hackathon — zero direct API calls, 100% MCP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Project managers track risks mentally but never systematically. When a task slips, nobody knows which 8 downstream tasks just broke their deadlines. Single points of failure hide in plain sight — one person quietly blocking an entire workstream. By the time anyone notices, the cascade has already happened.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Solution&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Risk Radar reads your Notion project databases, builds a dependency graph, and surfaces risks that humans miss. It writes actionable risk reports back to Notion and automatically propagates deadline changes through the dependency chain.&lt;/p&gt;
&lt;p&gt;Mark one task late → watch 8 downstream dates shift automatically.&lt;/p&gt;
&lt;p&gt;Everything runs through the Model Context Protocol (MCP) — zero direct Notion API calls.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How It Works&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read&lt;/strong&gt; — Fetches all projects and tasks from Notion via MCP, including dependency…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lewisawe/risk-radar" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;h3&gt;
  
  
  Reading a dependency graph through MCP
&lt;/h3&gt;

&lt;p&gt;The Tasks database has a self-referencing "Depends On" relation. Reading this through MCP takes three steps per task: fetch the database to get the data source URL, search to get page IDs, then fetch each page individually to get its properties.&lt;/p&gt;

&lt;p&gt;The properties come back inside a &lt;code&gt;&amp;lt;properties&amp;gt;&lt;/code&gt; XML block as JSON. Relation fields like "Depends On" and "Project" are arrays of Notion page URLs. So building the graph means parsing URLs like &lt;code&gt;https://www.notion.so/abc123def456&lt;/code&gt;, stripping the prefix and dashes, and using the normalized ID as the graph node key. Without that normalization step, every dependency lookup fails silently and you get an empty graph. That bug cost me an hour.&lt;/p&gt;

&lt;h3&gt;
  
  
  The graph algorithms
&lt;/h3&gt;

&lt;p&gt;Once the tasks are in memory with their dependencies resolved to names, the risk engine runs four analyses:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critical path&lt;/strong&gt; uses DFS with memoization from root tasks (tasks with no upstream dependencies). It finds the longest chain through the dependency graph. This tells you which sequence of tasks has zero slack — if any of them slip, the project end date moves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single point of failure detection&lt;/strong&gt; does a recursive downstream traversal per task owner. If one person's incomplete tasks collectively block two or more downstream tasks, they're flagged. This catches the scenario where one engineer is quietly blocking an entire workstream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At-risk detection&lt;/strong&gt; is simpler: compare each task's deadline to today. Overdue tasks, tasks due within 3 days that haven't started, and tasks due tomorrow that are still in progress all get flagged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cascade impact&lt;/strong&gt; runs BFS from each at-risk task to enumerate every downstream task that would be affected by a slip.&lt;/p&gt;

&lt;p&gt;The risk score combines these: &lt;code&gt;overdue_ratio × 40 + spof_penalty (capped at 30) + cascade_penalty (capped at 30)&lt;/code&gt;. It's a rough heuristic, but it produces scores that feel right. A project with one overdue task and no dependencies scores low. A project with an overdue task that blocks 5 others through a single owner scores high.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing reports and cascading deadlines
&lt;/h3&gt;

&lt;p&gt;The risk report is a Markdown page created with &lt;code&gt;notion-create-pages&lt;/code&gt;. It includes the risk score with an emoji indicator (🔴/🟡/🟢), the critical path, at-risk tasks with reasons, SPOFs with the tasks they're blocking, and cascade impact chains. A separate Health History entry logs the score with a date for trend tracking.&lt;/p&gt;

&lt;p&gt;The cascade feature is the most interesting MCP interaction. When the scan finds an overdue task, it calculates the slip in days, then does a BFS through the dependency graph. For each downstream task that isn't done, it calls &lt;code&gt;notion-update-page&lt;/code&gt; with the new deadline using the &lt;code&gt;"date:Deadline:start"&lt;/code&gt; property format. A 5-task cascade means 5 sequential MCP update calls. Each one shifts a real deadline in Notion.&lt;/p&gt;

&lt;h3&gt;
  
  
  What surprised me about Notion MCP
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;notion-search&lt;/code&gt; results don't include full properties. You get page IDs and titles, but to read "Depends On" or "Deadline" you need a separate &lt;code&gt;notion-fetch&lt;/code&gt; per page. For 8 tasks across 3 projects, that's about 25 MCP calls just to read the data. It works, but it means the agent is I/O bound rather than compute bound. The graph algorithms themselves run in microseconds. The MCP calls take seconds.&lt;/p&gt;

&lt;p&gt;The other surprise was date properties. Setting a date requires two properties: &lt;code&gt;"date:Deadline:start"&lt;/code&gt; for the value and &lt;code&gt;"date:Deadline:is_datetime": 0&lt;/code&gt; to indicate it's a date-only field. Missing the second one doesn't error, but the date renders differently in Notion.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Built an Agent That Assembles Incident War Rooms in Notion Through MCP</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 29 Mar 2026 21:48:42 +0000</pubDate>
      <link>https://dev.to/lewisawe/i-built-an-agent-that-assembles-incident-war-rooms-in-notion-through-mcp-2idk</link>
      <guid>https://dev.to/lewisawe/i-built-an-agent-that-assembles-incident-war-rooms-in-notion-through-mcp-2idk</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;Incident Runbook is an agent that turns Notion into a living incident response system. It watches an Incidents database, and when a new SEV1 or SEV2 appears, it cross-references three other databases (Services, Runbooks, On-Call), assembles a War Room page with everything the responder needs, and writes it back to Notion. When the incident is marked resolved, it generates an AI post-mortem with Gemini 2.5 Flash.&lt;/p&gt;

&lt;p&gt;The whole thing runs through Notion's MCP server. No REST calls, no webhooks, no middleware layer.&lt;/p&gt;

&lt;p&gt;I built this because incident response at most companies is still a manual scramble. The runbook exists somewhere, the on-call schedule is in a different tool, and the service dependency map is in someone's head. This agent pulls all of that together in seconds.&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&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/lewisawe" rel="noopener noreferrer"&gt;
        lewisawe
      &lt;/a&gt; / &lt;a href="https://github.com/lewisawe/incident-runbook" rel="noopener noreferrer"&gt;
        incident-runbook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;🚨 Incident Runbook — AI-Powered Incident Response for Notion&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Built for the Notion MCP Hackathon — zero direct API calls, 100% MCP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;When a SEV1 hits at 2am, engineers scramble: "Where's the runbook? Who's on-call? What depends on this service?" They're copy-pasting from scattered docs, pinging Slack, and losing precious minutes. Incident response shouldn't require tribal knowledge — it should be automated.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Solution&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Incident Runbook turns your Notion workspace into a living incident response system. Log an incident → a full war room assembles itself in seconds.&lt;/p&gt;
&lt;p&gt;It connects to Notion entirely through the Model Context Protocol (MCP) — reading databases, assembling pages, and writing post-mortems without a single direct API call.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How It Works&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detect&lt;/strong&gt; — Scans your Incidents database for new SEV1/SEV2/SEV3 entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lookup&lt;/strong&gt; — Finds the affected service, pulls its runbook, maps dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assemble&lt;/strong&gt; — Creates a War Room page with
&lt;ul&gt;
&lt;li&gt;Incident details and…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lewisawe/incident-runbook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;h3&gt;
  
  
  The four-database pattern
&lt;/h3&gt;

&lt;p&gt;The agent coordinates across four Notion databases in a single scan: Incidents, Services, Runbooks, and On-Call. Each scan starts with &lt;code&gt;notion-search&lt;/code&gt; on the Incidents database to find new or resolved entries. For each incident, it follows the "Affected Service" relation to the Services database, then follows the "Runbook" relation from that service to the Runbooks database, and pulls contacts from the On-Call database filtered by role.&lt;/p&gt;

&lt;p&gt;This means a single incident triggers reads across all four databases. The MCP call pattern looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;notion-fetch&lt;/code&gt; on the database ID to get the &lt;code&gt;collection://&lt;/code&gt; data source URL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notion-search&lt;/code&gt; with that URL to get page IDs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notion-fetch&lt;/code&gt; on each page to get properties and content&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a scan with 1 incident, 3 services, 2 runbooks, and 4 on-call contacts, that's roughly 20 MCP calls. Chatty, but each call is fast and the total scan takes a few seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relation resolution was the trickiest part
&lt;/h3&gt;

&lt;p&gt;Notion MCP returns relation properties as arrays of page URLs, not IDs. So an incident's "Affected Service" looks like &lt;code&gt;["https://www.notion.so/abc123def456"]&lt;/code&gt; rather than a clean ID. Matching that to the actual service record means parsing the URL, stripping dashes, and normalizing to a consistent format across all four databases.&lt;/p&gt;

&lt;p&gt;I spent more time debugging ID mismatches than writing the actual war room assembly. Services fetched from the database had IDs in one format, while the relation URLs from incidents had them in another. The fix was normalizing everything to dashless hex strings on read.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Markdown back to Notion
&lt;/h3&gt;

&lt;p&gt;The war room page is a single Markdown string that Notion renders natively. It includes a details table, on-call contacts list, the full runbook steps, dependent services, a timeline, and an action checklist with checkboxes. Creating it is one &lt;code&gt;notion-create-pages&lt;/code&gt; call with the incident page as the parent.&lt;/p&gt;

&lt;p&gt;The post-mortem works the same way. The agent calculates MTTR from the incident creation time to resolution, feeds the incident details and timeline to Gemini 2.5 Flash, and writes the AI output into a new page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Watch mode and connection reuse
&lt;/h3&gt;

&lt;p&gt;The agent has a &lt;code&gt;watch&lt;/code&gt; mode that polls every 30 seconds. An early version spawned a new &lt;code&gt;mcp-remote&lt;/code&gt; process on every poll cycle, which ate system resources fast. The fix was extracting the scan logic into a function that accepts an existing MCP client, so &lt;code&gt;watch&lt;/code&gt; creates one connection and reuses it across all cycles.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'd do differently
&lt;/h3&gt;

&lt;p&gt;The property parsing is fragile. Properties come back inside a &lt;code&gt;&amp;lt;properties&amp;gt;&lt;/code&gt; XML block as JSON, and the key names are case-sensitive and sometimes inconsistent (I found both &lt;code&gt;"status"&lt;/code&gt; and &lt;code&gt;"Status"&lt;/code&gt; depending on how the database was configured). A more robust version would normalize property keys on read. But for a hackathon, regex and case-checking got the job done&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>Solving Halloween with Google Gemini and Iterative Image Generation</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Wed, 04 Mar 2026 11:25:41 +0000</pubDate>
      <link>https://dev.to/lewisawe/solving-halloween-with-google-gemini-and-iterative-image-generation-em4</link>
      <guid>https://dev.to/lewisawe/solving-halloween-with-google-gemini-and-iterative-image-generation-em4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/mlh-built-with-google-gemini-02-25-26"&gt;Built with Google Gemini: Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built with Google Gemini
&lt;/h2&gt;

&lt;p&gt;I built an AI Halloween Costume Generator because picking a costume is harder than it should be. You either spend hours scrolling through the same generic ideas online, or you have a vague concept but no clue how to actually make it. I wanted something that could take any input a text idea, a photo, or literally nothing and turn it into a complete DIY guide with materials, steps, and visuals.&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%2Fjxabzsfg8m9sanl84owx.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%2Fjxabzsfg8m9sanl84owx.png" alt="Horse Courasel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app works three ways. You can search for costume ideas by typing anything ("costumes for my dog," "spooky sci-fi"), and it gives you five different concepts to pick from. You can upload a photo of an object, person, or pet, and it generates a costume based on that image. Or if you're completely stuck, there's a "Surprise Me" button that creates something random.&lt;/p&gt;

&lt;p&gt;Once you pick an idea, you get a full breakdown with materials, estimated cost, difficulty level, and step-by-step instructions. The interesting part is the visuals. Instead of generic stock photos or disconnected diagrams, each instruction step has an image that builds on the previous one. You literally watch the costume come together piece by piece.&lt;/p&gt;

&lt;p&gt;I used three different Gemini models for this. gemini-2.5-flash handles all the text generation and structured data costume names, descriptions, materials lists, instructions. I defined a JSON schema so the output is always consistent and easy to work with. imagen-4.0-generate-001 creates the first image for each costume guide. Then gemini-2.5-flash-image-preview does something cool it takes the previous step's image and adds the new elements described in the current step. So instead of generating five separate images, it's building one image progressively.&lt;/p&gt;

&lt;p&gt;That additive image generation was the hardest part to get right. The model needs to understand what's already in the image, what the text is asking it to add, and how to blend them naturally. It took experimentation to figure out the right prompts and image parameters, but when it works, it makes the instructions way easier to follow than text alone.&lt;/p&gt;

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

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://halloween-costume-generator-610288702971.us-west1.run.app/"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




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

&lt;p&gt;I learned that multimodal doesn't just mean "uses images and text." It's about how those modes interact. The additive image feature only works because the model can see the previous image and understand the text instruction at the same time. That's different from just generating images from text prompts.&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%2F6cewlwhjjbh46on1zxpe.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%2F6cewlwhjjbh46on1zxpe.png" alt="Ghost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Structured outputs made this project manageable. Without the JSON schema, I'd be parsing freeform text and dealing with inconsistent formats. With it, I know exactly what I'm getting back every time, which makes building a UI straightforward.&lt;/p&gt;

&lt;p&gt;The search feature taught me something about prompt design. Asking for "five costume ideas" in one call is way more efficient than making five separate calls, and the results are actually more diverse because the model can differentiate them in context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Gemini Feedback
&lt;/h2&gt;

&lt;p&gt;The image editing model (gemini-2.5-flash-image-preview) was the star here. Being able to iteratively build on an image is powerful and not something I've seen done well elsewhere. It worked better than I expected for this use case.&lt;/p&gt;

&lt;p&gt;Structured outputs continue to be essential. They're the difference between a prototype and something you can actually ship.&lt;/p&gt;

&lt;p&gt;The friction came from tuning the image generation. Sometimes the additive steps would drift from the original concept, or the model would reinterpret elements instead of just adding to them. I had to be specific in the prompts about what to preserve and what to add. It wasn't a model limitation as much as figuring out how to communicate clearly with it.&lt;/p&gt;

&lt;p&gt;One thing I'd like is better control over image composition in the editing model. Being able to specify regions or layers would make the additive process more predictable. But overall, the multimodal capabilities let me build something I couldn't have built otherwise.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>geminireflections</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Qwani Connect, the Nairobi's Young Creatives Community Hub</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 01 Mar 2026 23:55:11 +0000</pubDate>
      <link>https://dev.to/lewisawe/qwani-connect-the-nairobis-young-creatives-community-hub-i2m</link>
      <guid>https://dev.to/lewisawe/qwani-connect-the-nairobis-young-creatives-community-hub-i2m</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;&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%2Fbmqnyddi88yyw8fq8lg9.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%2Fbmqnyddi88yyw8fq8lg9.png" alt="Abou Qwani"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Qwani is a youth-led creative community based in Nairobi, Kenya. What started as a platform for young writers to get published has grown into a home for artists, musicians, film-makers, illustrators, poets, and anyone who creates.&lt;/p&gt;

&lt;p&gt;Every month, Qwani hosts events that bring people together in ways that are hard to find anywhere else in the city:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hikes&lt;/strong&gt; "positive suffering," as the community calls it. Last Saturday of every month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sketch Tours&lt;/strong&gt; along Nairobi,  walk, learn the history of iconic buildings like Kipande House and McMillan Library, and sketch the city around you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poetry &amp;amp; Letter Reading Sessions&lt;/strong&gt; at the American Corner on Moi Avenue, submit a poem or an unconventional letter, and the group reads and openly critiques it together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trivia Nights&lt;/strong&gt; — board games, Kahoot, and team quizzes. Think you know all 55 African capitals?&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%2Fhnmffki4607s50ifvume.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%2Fhnmffki4607s50ifvume.png" alt="Qwani Events"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Mics&lt;/strong&gt; — poets, musicians, and spoken-word artists get a stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Karaoke &amp;amp; Crafts&lt;/strong&gt; — sing Sauti Sol with your friends while others learn bead-making and crochet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Picnics&lt;/strong&gt; at the Arboretum, &lt;strong&gt;Cycling Tours&lt;/strong&gt; through Karura Forest, and &lt;strong&gt;Book Discussions&lt;/strong&gt; with author panels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm part of this community, and I built Qwani Connect for them.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Qwani Connect&lt;/strong&gt; is a community platform that solves three real problems I noticed:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Event Discovery &amp;amp; RSVP
&lt;/h3&gt;

&lt;p&gt;Qwani's events are currently scattered across Instagram stories, WhatsApp groups, and word of mouth. Qwani Connect puts every event in one place with RSVP functionality and a real-time &lt;strong&gt;"Who's Going"&lt;/strong&gt; feature, you can see avatar initials of people who've RSVP'd, creating social proof and FOMO before you even commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Wall — A Live Poetry &amp;amp; Writing Feed
&lt;/h3&gt;

&lt;p&gt;Currently, members submit poems and letters via email before reading sessions. Qwani Connect replaces that with &lt;strong&gt;The Wall&lt;/strong&gt; a live masonry-layout feed where submitted poems, letters, and stories appear instantly for the whole community to read and heart.&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%2Fyeciqqexkmvrhtca71kx.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%2Fyeciqqexkmvrhtca71kx.png" alt="The Wall"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Wall uses &lt;strong&gt;Supabase Realtime&lt;/strong&gt; — when someone submits a new piece, it appears for everyone without a page refresh. The feed is multilingual, just like the community English, Swahili, and Sheng all live side by side.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Suffering Streak
&lt;/h3&gt;

&lt;p&gt;Qwani's monthly hikes are legendary. The community bonds through what they call "positive suffering." I turned this inside joke into a feature: &lt;strong&gt;The Suffering Streak&lt;/strong&gt; tracks your consecutive monthly hike attendance with a leaderboard.&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%2Fgizotewbmf4w25i3r2vi.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%2Fgizotewbmf4w25i3r2vi.png" alt="Streak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Miss a month? Your streak resets. The fire emojis scale with your commitment — 🔥 for beginners, 🔥🔥 for regulars, 🔥🔥🔥 for the truly committed. It's gamification that only makes sense if you know this community, and that's exactly the point.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://main.d1ledrbyelrj6q.amplifyapp.com/" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Check out the Live Demo&lt;/a&gt;
&lt;/p&gt;

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

&lt;p&gt;[GitHub Repo for Qwani Connect]{&lt;a href="https://github.com/lewisawe/qwani-connect" rel="noopener noreferrer"&gt;https://github.com/lewisawe/qwani-connect&lt;/a&gt;}&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Next.js 16&lt;/strong&gt; (App Router)&lt;/td&gt;
&lt;td&gt;Server components for fast initial load, API routes for backend logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Supabase&lt;/strong&gt; (Postgres + Realtime)&lt;/td&gt;
&lt;td&gt;Realtime subscriptions for The Wall and Who's Going, Row Level Security, instant setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icons&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lucide React&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clean, consistent iconography&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Amplify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hosting with CI/CD from GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Database Design
&lt;/h3&gt;

&lt;p&gt;Four tables with Row Level Security:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;events&lt;/span&gt;      &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rsvp_count&lt;/span&gt;
&lt;span class="n"&gt;rsvps&lt;/span&gt;       &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;unique&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;submissions&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poem&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;story&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;streaks&lt;/span&gt;     &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hike_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_streak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_hike_month&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Postgres trigger auto-increments &lt;code&gt;rsvp_count&lt;/code&gt; when a new RSVP is inserted. The streak API calculates month-over-month continuity server-side to prevent gaming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realtime Features
&lt;/h3&gt;

&lt;p&gt;Two features use Supabase Realtime subscriptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Wall&lt;/strong&gt; subscribes to &lt;code&gt;INSERT&lt;/code&gt; events on &lt;code&gt;submissions&lt;/code&gt; — new poems appear instantly for all viewers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who's Going&lt;/strong&gt; subscribes to &lt;code&gt;INSERT&lt;/code&gt; events on &lt;code&gt;rsvps&lt;/code&gt; filtered by &lt;code&gt;event_id&lt;/code&gt; — new RSVPs show up live on event cards&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What Makes This Different
&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%2Fvi43f1yx3jm2uhuuc7x2.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%2Fvi43f1yx3jm2uhuuc7x2.png" alt="Qwani iko nini"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Suffering Streak is technically just a counter with date logic, but it resonates because it's built on an inside joke. The Wall is a living space where Sheng poems sit next to Swahili letters sit next to English stories, exactly like a real Qwani session.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building env-doctor with GitHub Copilot CLI</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 15 Feb 2026 23:09:49 +0000</pubDate>
      <link>https://dev.to/lewisawe/building-env-doctor-with-github-copilot-cli-55m7</link>
      <guid>https://dev.to/lewisawe/building-env-doctor-with-github-copilot-cli-55m7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built env-doctor, a CLI tool that automatically checks if your local environment matches what your project expects. You know that frustrating moment when you clone a project and spend an hour figuring out why it won't run? Usually it's missing Node versions, environment variables, or services that weren't mentioned clearly in the README. This tool solves that.&lt;/p&gt;

&lt;p&gt;It scans your project files - package.json, Dockerfile, docker-compose.yml, README, CI configs, and more - then extracts what the project actually needs. After that, it checks your local setup and gives you a clear checklist of what's working and what needs fixing. Instead of hunting through documentation, you get a direct report: "Node.js ✅, Docker ✅, PostgreSQL ❌ not running, DATABASE_URL ❌ missing."&lt;/p&gt;

&lt;p&gt;The tool covers runtime versions, package managers, databases, services, environment variables, and port availability. It works with Node.js, Python, Go projects and gives you actionable suggestions for fixing issues. There's also JSON output for CI pipelines and a verbose mode that explains everything it found.&lt;/p&gt;

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

&lt;p&gt;The tool is available at &lt;a href="https://github.com/lewisawe/env-doctor" rel="noopener noreferrer"&gt;github.com/env-doctor&lt;/a&gt; with a comprehensive example project that demonstrates all features.&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%2Feyxr4qnvdvmt7hqajjaj.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%2Feyxr4qnvdvmt7hqajjaj.png" alt="Env-Doctor" width="682" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what happens when you run it on a complex project:&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="nv"&gt;$ &lt;/span&gt;env-doctor &lt;span class="nt"&gt;--verbose&lt;/span&gt;

env-doctor - Analyzing project environment...

Runtime Versions:
✅ Node.js 18.17.0 &lt;span class="o"&gt;(&lt;/span&gt;required: &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;18.0.0&lt;span class="o"&gt;)&lt;/span&gt;
✅ Docker running &lt;span class="o"&gt;(&lt;/span&gt;v24.0.7&lt;span class="o"&gt;)&lt;/span&gt;
❌ Python 3.8.10 &lt;span class="o"&gt;(&lt;/span&gt;required: &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;3.9.0&lt;span class="o"&gt;)&lt;/span&gt;

Services:
❌ redis not found
✅ PostgreSQL accessible on port 5432

Environment Variables:
❌ DATABASE_URL environment variable not &lt;span class="nb"&gt;set&lt;/span&gt;
❌ JWT_SECRET environment variable not &lt;span class="nb"&gt;set&lt;/span&gt;
✅ &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development

📊 Results: 4/8 checks passed &lt;span class="o"&gt;(&lt;/span&gt;4 failed&lt;span class="o"&gt;)&lt;/span&gt;
❌ Environment needs attention

 Next steps:
1. Update Python to &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;3.9.0
2. Install and start redis
3. Set DATABASE_URL environment variable
4. Set JWT_SECRET environment variable
&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%2Fgv6p2j48i0enm5w5izba.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%2Fgv6p2j48i0enm5w5izba.png" alt="Runtime and services" width="700" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example project I included shows off the tool's capabilities with a realistic full-stack application. It has Node.js, Python, and Go services, multiple databases, complex Docker setup, and tons of environment variables. When you run env-doctor on it, you get 13/59 checks passing, which perfectly demonstrates how the tool handles complex real-world projects.&lt;/p&gt;

&lt;p&gt;I also built a simple demo script that explains what each file type contributes to the analysis. You can clone the repo and run &lt;code&gt;cd example-project &amp;amp;&amp;amp; ./demo.sh&lt;/code&gt; to see everything in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;Using GitHub Copilot CLI completely changed how I approached this project. Instead of writing code bit by bit, I could focus on the bigger picture and let Copilot handle the implementation details.&lt;/p&gt;

&lt;p&gt;The most helpful part was how Copilot understood context across multiple files. When I described the file parsing requirements, it generated parsers for package.json, Dockerfile, docker-compose.yml, and CI configs all at once. Each parser was tailored to extract the right information - Node versions from package.json, base images from Dockerfiles, services from docker-compose files.&lt;/p&gt;

&lt;p&gt;What impressed me was how it handled the environment checking logic. I explained that I needed to verify Node versions, check if Docker is running, test database connectivity, and validate environment variables. Copilot created a comprehensive checking system with proper error handling and meaningful status messages.&lt;/p&gt;

&lt;p&gt;The CLI also helped with the user experience aspects I hadn't initially planned. It suggested adding colored output with emoji indicators, a verbose mode for detailed explanations, JSON output for CI integration, and helpful suggestions for fixing issues. These weren't things I explicitly asked for, but Copilot recognized they would make the tool more useful.&lt;/p&gt;

&lt;p&gt;Testing was another area where Copilot excelled. It created unit tests for individual components and an integration test that builds a temporary project structure to verify everything works together. The test coverage caught several edge cases I would have missed.&lt;/p&gt;

&lt;p&gt;The most significant impact was being able to iterate quickly on complex features. When I wanted to add support for Python projects, Copilot immediately understood I needed requirements.txt and pyproject.toml parsers, Python version checking, and pip availability tests. What would have taken me hours of research and implementation happened in minutes.&lt;/p&gt;

&lt;p&gt;Copilot also helped with the example project creation. I described wanting a comprehensive test case, and it built a realistic social media application with multiple languages, databases, microservices, and CI/CD pipelines. This wasn't just a toy example - it's the kind of complex project where env-doctor actually provides value.&lt;/p&gt;

&lt;p&gt;The experience showed me how AI tools can handle the mechanical aspects of programming while leaving the creative and strategic decisions to the human developer. I focused on the problem design and user experience while Copilot handled the implementation patterns, error cases, and integration detail&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Why My Portfolio Has Superpowers and Villain Galleries</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sat, 31 Jan 2026 16:56:41 +0000</pubDate>
      <link>https://dev.to/lewisawe/why-my-portfolio-has-superpowers-and-villain-galleries-1hci</link>
      <guid>https://dev.to/lewisawe/why-my-portfolio-has-superpowers-and-villain-galleries-1hci</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;When I started thinking about my portfolio, I realized most developer portfolios look the same. Clean, minimal, professional. Nothing wrong with that, but it wasn't really me. I wanted something that showed I can do the technical work but also that I don't take myself too seriously. That's where the comic book theme came from. It's a bit ridiculous, but it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://comic-portfolio-610288702971.us-central1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




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

&lt;p&gt;Built this with React 19 and TypeScript because I wanted type safety and didn't want to deal with prop-type headaches. Used Vite for the build setup since it's fast and doesn't require much configuration. Tailwind handled the styling with a custom theme I put together using comic book colors and those classic comic effects like rotated text and bold borders.&lt;/p&gt;

&lt;p&gt;For the data visualization stuff showing skill levels, I used Recharts. It's straightforward and does what I needed without overcomplicating things. The whole thing runs in a Docker container and deploys to Google Cloud Run, which made sense since that's what the challenge required anyway.&lt;/p&gt;

&lt;p&gt;I used Google AI Studio and Gemini to help with the content. Writing about yourself is weird, so I had it help brainstorm section names and refine some of the project descriptions. It was useful for keeping the comic book voice consistent without going overboard. I'd feed it my rough notes about projects and it'd help make them more readable while keeping them honest.&lt;/p&gt;

&lt;p&gt;The comic book theme isn't just decoration. Instead of calling things "Skills" and "Projects," I went with "Superpowers" and "Missions." There's a "Villain Gallery" section where I talk about actual problems I've dealt with, like systems going down for hours or AWS bills getting out of control. Each one shows what the problem was, how I fixed it, and what changed. It's more interesting than just listing technologies.&lt;/p&gt;

&lt;p&gt;Added some interactive stuff too. There's a Konami Code easter egg if you're into that sort of thing, and a click combo system that triggers effects if you click fast enough. Floating particles in the background give it some movement without being distracting. These weren't necessary but they made it more fun to build.&lt;/p&gt;

&lt;p&gt;The deployment was straightforward. Multi-stage Docker build where Node compiles everything, then Nginx serves the static files. Keeps the final image small, around 50MB. Cloud Run handles the scaling and HTTPS automatically, and I added the required label for the challenge. The whole setup deploys in a few minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;The theme actually works. Every section fits the comic book idea without feeling forced. Hover effects show "KAPOW!" and "ZAP!" text, section headers are rotated like comic panels, and the color scheme stays consistent. It's cohesive but not overwhelming.&lt;/p&gt;

&lt;p&gt;Behind all the comic book stuff, the content is real. I've got 9 cloud certifications, projects that range from serverless games to chaos engineering experiments, and actual results from work I've done. One project cut downtime by 95%, another reduced cloud costs by 35%. The fun presentation doesn't hide that there's substance underneath.&lt;/p&gt;

&lt;p&gt;The interactive elements turned out better than I expected. The Konami Code works, the click combos feel responsive, and the floating particles add just enough movement. I also made sure it's accessible with proper semantic HTML and ARIA labels, and it's fully responsive. Tested it on mobile and it holds up.&lt;/p&gt;

&lt;p&gt;Performance is solid too. Lighthouse scores are in the mid-90s across the board. The Docker image is optimized, and Cloud Run's auto-scaling means it handles traffic spikes without me thinking about it. It's set up properly for production even though it's a portfolio site.&lt;/p&gt;

&lt;p&gt;Honestly, I'm just glad I built something that shows what I can do technically while also showing I'm not a robot. If someone looks at this and thinks "this person knows their stuff but seems like they'd be decent to work with," then it did its job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Site:&lt;/strong&gt; &lt;a href="https://comic-portfolio-610288702971.us-central1.run.app" rel="noopener noreferrer"&gt;https://comic-portfolio-610288702971.us-central1.run.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/lewisawe" rel="noopener noreferrer"&gt;https://github.com/lewisawe&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://linkedin.com/in/lewisawe" rel="noopener noreferrer"&gt;https://linkedin.com/in/lewisawe&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Building Multi-Agent AWS Operations Intelligence with Amazon Bedrock AgentCore</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Mon, 29 Sep 2025 15:31:46 +0000</pubDate>
      <link>https://dev.to/aws-builders/building-multi-agent-aws-operations-intelligence-with-amazon-bedrock-agentcore-1enm</link>
      <guid>https://dev.to/aws-builders/building-multi-agent-aws-operations-intelligence-with-amazon-bedrock-agentcore-1enm</guid>
      <description>&lt;p&gt;We set out to build something that didn't exist yet - a multi-agent AI system that could automatically discover AWS environments and provide real operations intelligence across entire organizations. The goal wasn't just to make another monitoring tool, but to create agents that could actually understand AWS infrastructure and costs in ways that existing tools couldn't.&lt;/p&gt;

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

&lt;p&gt;The AWS Operations Command Center is a three-agent system built on Amazon Bedrock AgentCore. Each agent specializes in a different aspect of AWS operations, but they work together to provide unified intelligence about your infrastructure.&lt;/p&gt;

&lt;p&gt;The Cost Intelligence Agent handles financial analysis across multiple AWS accounts. It doesn't just pull billing data - it separates actual usage costs from credits to show you what you're really consuming. Most AWS billing tools show you net costs after credits, which hides your actual usage patterns. Our agent discovered $255.22 in real usage across our three-account organization that was almost completely offset by $255.21 in credits, leaving a final bill of just $0.01.&lt;/p&gt;

&lt;p&gt;The Operations Intelligence Agent scans resources across your entire AWS organization. It uses cross-account roles to inventory everything from EC2 instances to S3 buckets to RDS databases. In our testing, it found 90 resources across our accounts that we could then analyze for security issues, performance bottlenecks, and optimization opportunities.&lt;/p&gt;

&lt;p&gt;The Infrastructure Intelligence Agent generates architecture recommendations and scores existing setups for security and reliability. It's not just templating - it analyzes your actual infrastructure and suggests improvements based on AWS best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AgentCore Implementation
&lt;/h2&gt;

&lt;p&gt;Getting these agents to work with Amazon Bedrock AgentCore was more challenging than expected. The documentation makes it look straightforward, but the reality involved a lot of trial and error.&lt;/p&gt;

&lt;p&gt;Each agent uses the AgentCore runtime framework. The basic structure looks like this:&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;bedrock_agentcore.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentCoreApp&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentCoreApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.entrypoint&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;session_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&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;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

    &lt;span class="c1"&gt;# Store session context in memory service
&lt;/span&gt;    &lt;span class="n"&gt;memory_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_id&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;agent&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;cost_intelligence&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;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;payload&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Process the request
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_multi_account_costs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Add AgentCore metadata
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;services_used&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;runtime&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;memory&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;gateway&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;session_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;session_id&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;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The memory service integration was crucial for getting agents to share context. When the cost agent discovers expensive resources, that information needs to be available to the operations agent for deeper analysis. We implemented a simple but effective memory service that stores session data with TTL expiration.&lt;/p&gt;

&lt;p&gt;Agent coordination happens through an orchestrator that can invoke agents either locally or through the AgentCore gateway. The orchestrator handles partial failures gracefully - if one agent fails, the others continue working and provide what insights they can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Discovery Architecture
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges was making the agents work in any AWS environment without manual configuration. Most tools require you to specify account IDs, regions, and access patterns upfront. We wanted agents that could figure out their environment automatically.&lt;/p&gt;

&lt;p&gt;The solution was environment discovery during agent initialization. Each agent detects whether it's running in an AWS Organizations management account by trying to call the Organizations API. If that succeeds, it knows it can do cross-account analysis. If not, it falls back to single-account mode.&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;def&lt;/span&gt; &lt;span class="nf"&gt;_discover_environment&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;sts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sts&lt;/span&gt;&lt;span class="sh"&gt;'&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;current_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_caller_identity&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Account&lt;/span&gt;&lt;span class="sh"&gt;'&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;organizations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;organizations&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;org_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="n"&gt;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe_organization&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;is_org_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

            &lt;span class="n"&gt;accounts&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;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_accounts&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;org_accounts&lt;/span&gt; &lt;span class="o"&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;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;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Id&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;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Name&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;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Accounts&lt;/span&gt;&lt;span class="sh"&gt;'&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;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ACTIVE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;except&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;is_org_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&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;org_accounts&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;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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_account_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&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;current&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;status&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;ACTIVE&lt;/span&gt;&lt;span class="sh"&gt;'&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="c1"&gt;# Handle gracefully
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach means you can deploy the same agent code anywhere and it adapts to its environment. Deploy it in a standalone account and it analyzes that account. Deploy it in an organization management account and it analyzes the entire organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Account Access Challenges
&lt;/h2&gt;

&lt;p&gt;Getting true multi-account analysis working was the hardest part. AWS has good security boundaries between accounts, which is great for isolation but challenging when you want unified operations intelligence.&lt;/p&gt;

&lt;p&gt;We solved this with cross-account IAM roles deployed via CloudFormation. Each member account gets an OrganizationAccountAccessRole that the management account can assume. The role has read-only permissions and requires an external ID for additional security.&lt;/p&gt;

&lt;p&gt;The deployment process uses the configured AWS profiles to push CloudFormation templates to each account:&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;def&lt;/span&gt; &lt;span class="nf"&gt;deploy_role_to_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;account_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&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="n"&gt;cf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cloudformation&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;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;StackName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aws-operations-command-center-role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TemplateBody&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;template_body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Capabilities&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;CAPABILITY_NAMED_IAM&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="n"&gt;waiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_waiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stack_create_complete&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StackName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aws-operations-command-center-role&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;Once the roles are deployed, agents can assume them to access resources in member accounts. The cost agent uses this to get billing data from each account separately, then aggregates it for organization-wide analysis. The operations agent uses it to scan resources across all accounts.&lt;/p&gt;

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

&lt;p&gt;The AgentCore CLI had reliability issues. The &lt;code&gt;agentcore deploy&lt;/code&gt; command failed more often than it worked, usually with cryptic IAM errors. Even with admin permissions, we'd hit edge cases where role creation would partially succeed, leaving broken deployments that were hard to clean up.&lt;/p&gt;

&lt;p&gt;The memory service had undocumented size limits that caused silent failures. Context data would just disappear without error messages, making debugging difficult. We ended up implementing our own memory service with proper error handling and size checks.&lt;/p&gt;

&lt;p&gt;Gateway service communication was unreliable under load, with intermittent connection failures. We built a fallback mechanism that uses local agent invocation when the gateway isn't available.&lt;/p&gt;

&lt;p&gt;Version compatibility between the AgentCore CLI and SDK was problematic. Upgrading would break existing configurations in ways that weren't well documented. We had to pin to specific versions and test thoroughly before any updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production-Ready Error Handling
&lt;/h2&gt;

&lt;p&gt;One thing we learned quickly was that AWS APIs fail in many different ways, and you need to handle each failure mode appropriately. We built a comprehensive error handling system that categorizes failures and responds accordingly.&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;def&lt;/span&gt; &lt;span class="nf"&gt;safe_aws_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&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;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ClientError&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;error_code&lt;/span&gt; &lt;span class="o"&gt;=&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;response&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;Code&lt;/span&gt;&lt;span class="sh"&gt;'&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;error_code&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Throttling&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;RequestLimitExceeded&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AccessDenied&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;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&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;access_denied&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&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;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&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="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="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;NoCredentialsError&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;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&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;no_credentials&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;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&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;max_retries_exceeded&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;This wrapper handles throttling with exponential backoff, distinguishes between different types of access errors, and provides meaningful error messages that agents can act on.&lt;/p&gt;

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

&lt;p&gt;Building multi-agent systems with AgentCore taught us that the framework is powerful but still rough around the edges. The core concepts are solid - the runtime, memory, and gateway services provide a good foundation for agent coordination. But the tooling needs work, especially around deployment and debugging.&lt;/p&gt;

&lt;p&gt;The self-discovery approach worked better than expected. Having agents that adapt to their environment makes deployment much simpler and reduces configuration errors. It also makes the system more resilient - agents continue working even when they can't access all the resources they'd like to.&lt;/p&gt;

&lt;p&gt;Cross-account analysis is valuable but complex. The security boundaries that make AWS safe also make unified operations intelligence challenging. The IAM role approach works, but it requires careful setup and ongoing maintenance.&lt;/p&gt;

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

&lt;p&gt;The final system provides genuine business value. It discovered $255.22 in AWS usage across our organization that was hidden by credits, giving us visibility into our actual consumption patterns. It inventoried 90 resources across multiple accounts, providing a unified view of our infrastructure that we didn't have before.&lt;/p&gt;

&lt;p&gt;More importantly, it demonstrates that multi-agent AI systems can solve real operational problems. The agents work together to provide insights that none of them could generate alone. The cost agent finds expensive resources, the operations agent analyzes them for optimization opportunities, and the infrastructure agent suggests architectural improvements.&lt;/p&gt;

&lt;p&gt;The system is production-ready with comprehensive error handling, structured logging, and graceful degradation when services are unavailable. It's not just a demo - it's a working operations intelligence platform that scales from single accounts to entire AWS organizations.&lt;/p&gt;

&lt;h3&gt;
  
  
  REFERENCES
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/lewisawe/silver-succotash/tree/main/agent" rel="noopener noreferrer"&gt;https://github.com/lewisawe/silver-succotash/tree/main/agent&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/bedrock/agentcore/" rel="noopener noreferrer"&gt;https://aws.amazon.com/bedrock/agentcore/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://strandsagents.com/latest/" rel="noopener noreferrer"&gt;https://strandsagents.com/latest/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets Connect - Lewis Sawe: &lt;a href="https://www.linkedin.com/in/lewisawe/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Buy me &lt;a href="https://buymeacoffee.com/lewisawe" rel="noopener noreferrer"&gt;coffee&lt;/a&gt; ☕&lt;/p&gt;

</description>
      <category>aws</category>
      <category>agentcore</category>
      <category>bedrock</category>
      <category>devops</category>
    </item>
    <item>
      <title>Spooky Smart AI That Designs Your Halloween Look</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 14 Sep 2025 21:51:31 +0000</pubDate>
      <link>https://dev.to/lewisawe/spooky-smart-ai-that-designs-your-halloween-look-2dil</link>
      <guid>https://dev.to/lewisawe/spooky-smart-ai-that-designs-your-halloween-look-2dil</guid>
      <description>&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%2Fwo12k19n2mcf7ozzpsja.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%2Fwo12k19n2mcf7ozzpsja.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-ai-studio-2025-09-03"&gt;Google AI Studio Multimodal Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built the AI Halloween Costume Generator, a comprehensive web application designed to solve the age-old problem of choosing the perfect Halloween costume. It acts as a creative partner, transforming vague ideas or even simple images into complete, ready-to-make costume guides.&lt;/p&gt;

&lt;h3&gt;
  
  
  The app provides a multi-faceted approach to inspiration:
&lt;/h3&gt;

&lt;p&gt;Search: Users can type in any theme or idea (e.g., "costumes for my dog," "spooky sci-fi ideas") and receive five distinct, fully-detailed costume concepts to compare and choose from.&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%2F3lx6ct9vlucwodz6brp7.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%2F3lx6ct9vlucwodz6brp7.png" alt="Image Ideas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generate from Image: Users can upload a photo of an object, a person, or a pet, and the AI will generate a unique costume concept based on the visual input.&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%2Fp7zbohg0g59do2nypyfs.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%2Fp7zbohg0g59do2nypyfs.png" alt="Generate from Images"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Surprise Me!: For users who are completely stumped, a "Surprise Me!" button generates a totally random and creative idea out of the blue.&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%2Fg13kbvxv766enhw1h3i3.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%2Fg13kbvxv766enhw1h3i3.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once an idea is selected, the app provides a complete DIY guide, including a list of materials, an estimated cost and difficulty level, and most importantly, detailed step-by-step instructions with custom-generated, additive illustrations that show the costume coming together.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;To try out:&lt;/strong&gt; &lt;a href="https://halloween-costume-generator-610288702971.us-west1.run.app/" rel="noopener noreferrer"&gt;Cloud Run Demo link&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  How I Used Google AI Studio
&lt;/h2&gt;

&lt;p&gt;I leveraged a suite of multimodal models from the Gemini API to power the application's core features, orchestrating them to create a seamless user experience.&lt;/p&gt;

&lt;p&gt;gemini-2.5-flash: This was the primary model for all text and structured data generation. I used it with a strictly defined responseSchema to ensure the AI's output was always in a predictable JSON format. This model was responsible for:&lt;/p&gt;

&lt;p&gt;Generating the costume's name, description, materials, and detailed text instructions.&lt;/p&gt;

&lt;p&gt;Powering the search feature by creating five distinct costume concepts from a single prompt.&lt;/p&gt;

&lt;p&gt;Handling the conversational "Refine" feature, where it would modify a costume based on follow-up user input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;imagen-4.0-generate-001:&lt;/strong&gt; This powerful image generation model was used to create the crucial first image for each set of instructions, establishing the visual foundation for the step-by-step guide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gemini-2.5-flash-image-preview:&lt;/strong&gt; This versatile image editing model was the key to creating the app's most unique feature. It was used to generate all subsequent instruction images by taking the previous step's image as input and adding the new details described in the current step's text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multimodal Features
&lt;/h2&gt;

&lt;p&gt;The app is built around two core multimodal functionalities that create a rich and intuitive user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vision Understanding: Image to Costume Idea&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ability for a user to upload an image and receive a relevant costume idea is a powerful multimodal feature. It goes beyond simple text prompts by allowing for visual context. A user can upload a picture of their pet, a favorite object, or a friend, and the AI can creatively interpret that visual data to generate a highly personalized and often unexpected costume concept. This makes the brainstorming process more personal and engaging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additive Image Generation: A Cohesive Visual Guide&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The app's standout feature is its ability to create a set of instruction images that build upon one another. Instead of generating a new, disconnected image for each step, the system uses an iterative, multimodal process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: Generate a base image from a text prompt.&lt;/li&gt;
&lt;li&gt;Step 2+: Feed the image from the previous step plus the text for the current step into the image editing model (gemini-2.5-flash-image-preview).&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%2Fda4cnmky8ct892vvv6e8.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%2Fda4cnmky8ct892vvv6e8.png" alt="Image steps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a coherent visual narrative, allowing the user to literally watch the costume come together from one image to the next. This significantly enhances the user experience by making the instructions far easier to understand and follow compared to a series of isolated diagrams. It transforms the app from a simple idea generator into a true step-by-step visual crafting guide.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>CLI for the Clueless, Learning AWS CLI Through Interactive Gaming</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Tue, 19 Aug 2025 22:47:16 +0000</pubDate>
      <link>https://dev.to/aws-builders/cli-for-the-clueless-learning-aws-cli-through-interactive-gaming-2b5l</link>
      <guid>https://dev.to/aws-builders/cli-for-the-clueless-learning-aws-cli-through-interactive-gaming-2b5l</guid>
      <description>&lt;p&gt;Forget boring tutorials and dry documentation. What if you could learn AWS CLI by solving mysteries, following clues, and completing challenges? What if mastering the command line felt more like playing a game than studying?&lt;/p&gt;

&lt;p&gt;I built an &lt;a href="https://lewisawe.github.io/laughing-potato/" rel="noopener noreferrer"&gt;AWS CLI Scavenger Hunt&lt;/a&gt; game that teaches you AWS CLI commands through progressive challenges and real-world scenarios. No installation required, no AWS account needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Try out the game hosted here -&lt;/strong&gt; &lt;a href="https://lewisawe.github.io/laughing-potato/" rel="noopener noreferrer"&gt;&lt;strong&gt;https://lewisawe.github.io/laughing-potato/&lt;/strong&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;h2&gt;
  
  
  Why Learn AWS CLI Through Gaming?
&lt;/h2&gt;

&lt;p&gt;Traditional learning methods for AWS CLI often fail because they're boring, abstract, intimidating, and passive. You read documentation that puts you to sleep, try to memorize commands without context, get scared away by the black terminal screen, and never actually practice what you're learning.&lt;/p&gt;

&lt;p&gt;Now instead of reading about commands, you're solving mysteries that keep you motivated. Every command has a purpose and story behind it, making the learning contextual and memorable. The progressive difficulty starts easy and builds complexity naturally, while you're actively typing commands from minute one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Your New Learning Platform
&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1755642359177%2Fbf125638-37fa-4fe4-b8ee-03e317708a84.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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1755642359177%2Fbf125638-37fa-4fe4-b8ee-03e317708a84.png" alt="screenshot" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://lewisawe.github.io/laughing-potato/" rel="noopener noreferrer"&gt;AWS CLI Scavenger Hunt&lt;/a&gt; simulates a real AWS environment directly in your browser. You'll type actual AWS commands, see authentic responses, and solve progressively challenging scenarios across multiple AWS services.&lt;/p&gt;

&lt;p&gt;The game covers over ten AWS services including S3, IAM, Lambda, DynamoDB, CloudFormation, Secrets Manager, CloudWatch, KMS, EC2, and VPC. Every command you learn uses real syntax with authentic responses, so the skills transfer directly to actual AWS work.&lt;/p&gt;

&lt;p&gt;Smart learning features enhance the experience throughout. Auto-completion shows you available commands as you type, complete with descriptions. A contextual help system provides service-specific guidance when you're stuck. Progressive hints appear after failed attempts, and an achievement system keeps you motivated to improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Learning Journey: From Zero to Hero
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Level 1: Beginner - "The S3 Mystery"
&lt;/h3&gt;

&lt;p&gt;Your journey begins with the fundamentals. You'll learn the basic command structure that all AWS CLI commands follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="o"&gt;[&lt;/span&gt;service] &lt;span class="o"&gt;[&lt;/span&gt;action] &lt;span class="o"&gt;[&lt;/span&gt;options]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first challenge presents you with a simple mystery: "Three buckets hold the key, but only one contains what you seek. List the S3 buckets to begin your quest..."&lt;/p&gt;

&lt;p&gt;When you type the command, you'll see a realistic response:&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="nv"&gt;$ &lt;/span&gt;aws s3 &lt;span class="nb"&gt;ls
&lt;/span&gt;2023-08-19 12:34:56 my-app-bucket
2023-08-19 12:35:12 clue-bucket-1
2023-08-19 12:35:28 backup-storage-bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One stands out: clue-bucket-1. The game then guides you to explore inside this bucket:&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="nv"&gt;$ &lt;/span&gt;aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://clue-bucket-1
2023-08-19 12:36:45        156 clue.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This teaches you how to navigate S3 storage and read responses. Each successful command reveals the next clue, creating a natural progression that builds confidence.&lt;/p&gt;

&lt;p&gt;By the end of the beginner level, you'll be comfortable with the command line interface, understand how to read AWS CLI output, know basic S3 navigation, and have developed a problem-solving mindset that serves you throughout your AWS journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  Level 2: Intermediate - "Multi-Service Investigation"
&lt;/h3&gt;

&lt;p&gt;The intermediate level introduces you to the real power of AWS CLI: working across multiple services. You'll start by investigating encrypted S3 buckets and CloudTrail logs, learning how different AWS services connect and share information.&lt;/p&gt;

&lt;p&gt;A typical challenge might reveal a Lambda function called 'log-processor' through your investigation. When you run the command, you'll discover environment variables pointing to encrypted SSM parameters:&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="nv"&gt;$ &lt;/span&gt;aws lambda get-function &lt;span class="nt"&gt;--function-name&lt;/span&gt; log-processor
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Configuration"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"FunctionName"&lt;/span&gt;: &lt;span class="s2"&gt;"log-processor"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Runtime"&lt;/span&gt;: &lt;span class="s2"&gt;"python3.9"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Environment"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Variables"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"SSM_PARAMETER_PATH"&lt;/span&gt;: &lt;span class="s2"&gt;"/advanced-hunt/encrypted-clue"&lt;/span&gt;,
                &lt;span class="s2"&gt;"LOG_LEVEL"&lt;/span&gt;: &lt;span class="s2"&gt;"INFO"&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This teaches you how to follow data flows across services, a crucial skill for real-world AWS work. You'll then retrieve the encrypted parameter:&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="nv"&gt;$ &lt;/span&gt;aws ssm get-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; /advanced-hunt/encrypted-clue &lt;span class="nt"&gt;--with-decryption&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Parameter"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"/advanced-hunt/encrypted-clue"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Type"&lt;/span&gt;: &lt;span class="s2"&gt;"SecureString"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Value"&lt;/span&gt;: &lt;span class="s2"&gt;"The final clue is in DynamoDB table 'hunt-secrets'"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Version"&lt;/span&gt;: 2
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The level progresses through Lambda function investigation, encrypted SSM parameters with decryption, and DynamoDB operations. You'll learn cross-service workflows, JSON parsing and analysis, encryption concepts, and real-world AWS patterns that professionals use daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Approach Works
&lt;/h2&gt;

&lt;p&gt;Learning by doing proves far more effective than memorizing syntax. Instead of trying to remember abstract commands, you discover them naturally through problem-solving. Each command has immediate purpose and visible results, making the learning stick.&lt;/p&gt;

&lt;p&gt;Contextual understanding develops as you see how S3 connects to Lambda, how SSM parameters work with DynamoDB, and how services integrate in real applications. This holistic view proves invaluable when working with actual AWS environments.&lt;/p&gt;

&lt;p&gt;Progressive complexity ensures you're never overwhelmed. You start with simple commands and gradually build to complex queries:&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;# Start simple&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;# Build complexity&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://bucket-name &lt;span class="nt"&gt;--recursive&lt;/span&gt;

&lt;span class="c"&gt;# Master advanced queries&lt;/span&gt;
aws ec2 describe-instances &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Reservations[].Instances[?State.Name=='running'].{ID:InstanceId,Type:InstanceType}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Immediate feedback accelerates learning. You don't wait for AWS responses or worry about costs. Every command provides instant feedback, with helpful hints when you're stuck. This rapid iteration helps you learn faster than traditional methods.&lt;/p&gt;

&lt;p&gt;Real-world relevance keeps you engaged. Every scenario is based on actual AWS use cases: troubleshooting applications, investigating security incidents, and analyzing infrastructure. The skills you develop apply directly to professional work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Game
&lt;/h2&gt;

&lt;p&gt;The commands you master in the game apply directly to professional AWS work. You'll learn essential AWS CLI patterns like identity and configuration commands:&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;# Check who you are&lt;/span&gt;
aws sts get-caller-identity

&lt;span class="c"&gt;# View your configuration&lt;/span&gt;
aws configure list

&lt;span class="c"&gt;# Get current region&lt;/span&gt;
aws configure get region
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;S3 operations become second nature:&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;# List buckets&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;# List bucket contents&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://my-bucket

&lt;span class="c"&gt;# Download files&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://my-bucket/file.txt &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Upload files&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;file.txt s3://my-bucket/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Advanced querying with JMESPath filters:&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;# Find running instances&lt;/span&gt;
aws ec2 describe-instances &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Reservations[].Instances[?State.Name=='running']"&lt;/span&gt;

&lt;span class="c"&gt;# Get instance IDs only&lt;/span&gt;
aws ec2 describe-instances &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Reservations[].Instances[].InstanceId"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text

&lt;span class="c"&gt;# Filter by tags&lt;/span&gt;
aws ec2 describe-instances &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Reservations[].Instances[?Tags[?Key=='Environment' &amp;amp;&amp;amp; Value=='production']]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-service workflows become second nature as you practice commands like:&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;# Get encrypted parameters&lt;/span&gt;
aws ssm get-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; /path/to/secret &lt;span class="nt"&gt;--with-decryption&lt;/span&gt;

&lt;span class="c"&gt;# Investigate Lambda functions&lt;/span&gt;
aws lambda get-function &lt;span class="nt"&gt;--function-name&lt;/span&gt; my-function

&lt;span class="c"&gt;# Query DynamoDB&lt;/span&gt;
aws dynamodb get-item &lt;span class="nt"&gt;--table-name&lt;/span&gt; MyTable &lt;span class="nt"&gt;--key&lt;/span&gt; &lt;span class="s1"&gt;'{"id":{"S":"item-id"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These patterns appear constantly in real AWS environments.&lt;/p&gt;

&lt;p&gt;The skills transfer directly to DevOps workflows for automating deployments and monitoring, security operations for investigating incidents and analyzing logs, cost optimization for finding and managing unused resources, troubleshooting for diagnosing application and infrastructure issues, and compliance work for auditing configurations and access patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Features for Serious Learners
&lt;/h2&gt;

&lt;p&gt;The achievement system rewards different types of mastery. Perfect Navigator recognizes completing levels with 90% efficiency, while Speed Demon celebrates finishing levels in record time. No Hints Needed acknowledges mastering commands without assistance, and Command Master honors conquering all difficulty levels.&lt;/p&gt;

&lt;p&gt;Smart learning tools enhance the experience throughout your journey. Auto-completion shows available commands as you type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &amp;lt;TAB&amp;gt;
&lt;span class="c"&gt;# Shows: cp, ls, mb, mv, rb, rm, sync, website&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Command history lets you navigate previous commands with arrow keys, contextual help provides service-specific guidance, and progress tracking monitors your improvement over time.&lt;/p&gt;

&lt;p&gt;The realistic simulation uses authentic AWS responses with real JSON output formats, proper error messages that teach you from realistic failure scenarios, service integration that shows how AWS services work together, and best practices with commands that follow AWS recommended patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Science Behind Game-Based Learning
&lt;/h2&gt;

&lt;p&gt;Research consistently shows that interactive, game-based learning increases retention by 75%, reduces learning time by 40%, improves problem-solving skills, and builds confidence faster than traditional methods. The science explains why this approach works so well for technical skills.&lt;/p&gt;

&lt;p&gt;Active learning engages you in doing rather than just reading. Immediate feedback lets you know instantly if you're right or wrong. Intrinsic motivation through curiosity drives you forward naturally. Spaced repetition reinforces commands through varied contexts. Flow state occurs when optimal challenge level keeps you engaged without overwhelming you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do you need an AWS account?&lt;/strong&gt; No! The game simulates AWS responses, so you can learn without any setup or costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if you get stuck?&lt;/strong&gt; The game provides progressive hints after failed attempts, plus contextual help for every service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How realistic are the scenarios?&lt;/strong&gt; Every challenge is based on real AWS use cases that professionals encounter daily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you use this to prepare for AWS certifications?&lt;/strong&gt; Absolutely! The commands and concepts directly apply to AWS certification exams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this suitable for complete beginners?&lt;/strong&gt; Yes! The Beginner level assumes no prior CLI or AWS experience.  &lt;/p&gt;

&lt;p&gt;Lets Connect - Lewis Sawe: &lt;a href="https://www.linkedin.com/in/lewisawe/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Buy me &lt;a href="https://buymeacoffee.com/lewisawe" rel="noopener noreferrer"&gt;coffee&lt;/a&gt; ☕&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>cli</category>
    </item>
    <item>
      <title>Creating a Plants Vs Zombies with Redis</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 10 Aug 2025 23:43:17 +0000</pubDate>
      <link>https://dev.to/lewisawe/creating-a-plants-vs-zombies-with-redis-2803</link>
      <guid>https://dev.to/lewisawe/creating-a-plants-vs-zombies-with-redis-2803</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Beyond the Cache&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;I developed a Plants vs. Zombies-inspired tower defense game that redefines what’s possible with Redis. This project uses Redis as the entire backend infrastructure. All game logic, state management, and real-time features are handled without a traditional SQL or NoSQL database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Game Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tower Defense:&lt;/strong&gt; Engage in real-time battles against waves of zombies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Leaderboards:&lt;/strong&gt; Compete for the top spot with five different real-time leaderboards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Game State:&lt;/strong&gt; Players can reconnect and resume their games exactly where they left off.
-** Dynamic Player Stats:** Track comprehensive, live statistics and player progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Username Suggestions:&lt;/strong&gt; Get creative, plant-themed username ideas automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Redis Powers the Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Redis is the engine behind the game. I utilized its diverse data structures to build a highly performant and scalable backend.&lt;/li&gt;
&lt;li&gt;Real-time Communication: Redis Pub/Sub handles all real-time events for multiplayer gameplay.&lt;/li&gt;
&lt;li&gt;Leaderboards: Redis sorted sets manage and update the live leaderboards, making it easy to rank players.&lt;/li&gt;
&lt;li&gt;Player Data: Game state and player statistics are stored using Redis hashes and other data structures for efficient access and updates.&lt;/li&gt;
&lt;li&gt;Analytics: Redis data structures track game metrics and analytics on the fly.&lt;/li&gt;
&lt;li&gt;Persistence: Redis's persistence features ensure that all game data is saved across sessions.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Here is the full Github Code you can test for yourself &lt;a href="https://github.com/lewisawe/super-adventure" rel="noopener noreferrer"&gt;Github Code&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;p&gt;This project demonstrates Redis using different Redis data structures to replace traditional database architectures:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Primary Database (Hashes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Redis completely replaces SQL databases&lt;/strong&gt;&lt;br&gt;
Redis stores all persistent data including complex nested game states, player profiles, and session information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Store complete game states as JSON&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:state`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;players&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="na"&gt;plants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
  &lt;span class="na"&gt;zombies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
  &lt;span class="na"&gt;currentWave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gameStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Player profiles with statistics and achievements  &lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`player:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:data`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;zombiesKilled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;plantsPlanted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gamesWon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_win&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;zombie_slayer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Real-Time Pub/Sub&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Live multiplayer without polling&lt;/strong&gt;&lt;br&gt;
All real-time updates use Redis Pub/Sub for sub-millisecond message delivery to unlimited concurrent players.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Broadcast plant placements to all players instantly&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:updates`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plant_placed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;plant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sunflower&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GardenMaster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Wave completion notifications&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:events`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wave_completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;wave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nextWaveIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wave 5 completed! Prepare for boss wave!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Event Sourcing (Streams)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Complete game replay and analytics pipeline&lt;/strong&gt;&lt;br&gt;
Provides complete event sourcing capabilities - every game action is recorded for replay, analytics, and debugging without external event streaming systems&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Record every game action for complete audit trail&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:events`&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plant_placed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ZombieSlayer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;plantType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;peashooter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;row&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="na"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Analytics pipeline processes all events&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gameEvents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:events`&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="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="c1"&gt;// Can reconstruct any game state from event history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;4. Leaderboards (Sorted Sets)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Real-time competitive rankings&lt;/strong&gt;&lt;br&gt;
Automatic ranking system with O(log N) performance - no manual sorting or separate ranking calculations needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Update multiple leaderboards simultaneously during gameplay&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard:high_scores&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard:zombies_killed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zombiesKilled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard:plants_planted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plantsPlanted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get top 10 players with scores instantly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;topPlayers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zrevrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard:high_scores&lt;/span&gt;&lt;span class="dl"&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="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WITHSCORES&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: [['EpicSunflower', '25840'], ['GardenMaster', '23150'], ...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5. Lane Management (Lists)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;FIFO zombie queues for game mechanics&lt;/strong&gt;&lt;br&gt;
Perfect queue management for game mechanics - zombies spawn and move in correct order with atomic operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Each game lane has its own zombie queue&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lpush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:lane:0:zombies`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;basic_zombie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;spawnTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Process zombies in spawn order (FIFO)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextZombie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rpop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:lane:0:zombies`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  👥 &lt;strong&gt;6. Session Management (Sets)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Active games and player tracking&lt;/strong&gt;&lt;br&gt;
Efficient session management with set operations - instant membership checks and lobby management without complex queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Track all active games&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active_games&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Track players in each game&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:players`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Efficient membership checks&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPlayerInGame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sismember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:players`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activeGameCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active_games&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;7. Analytics &amp;amp; Metrics (HyperLogLog + Counters)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Memory-efficient statistics&lt;/strong&gt;&lt;br&gt;
Memory-efficient unique counting, global statistics, and rate limiting without external analytics systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// HyperLogLog for unique player counting (uses only ~12KB for millions of players)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pfadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hll:unique_players&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uniquePlayerCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pfcount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hll:unique_players&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Global game statistics&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter:total_games&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incrby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter:zombies_killed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zombiesKilledThisGame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incrby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter:plants_planted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plantsPlantedThisGame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Rate limiting with expiring counters&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`rate_limit:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentHour&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`rate_limit:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentHour&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Traditional Redis Usage&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What most applications do - Redis as cache layer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&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="s2"&gt;`cache:user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cachedUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = ?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`cache:user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Redis as Complete Platform&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What this project demonstrates - Redis as the entire backend&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GameEngine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Redis IS the database, not a cache&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;placePlant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plantType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Primary Database: Update game state&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:state`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... modify game state ...&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:state`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gameState&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Real-time: Notify all players instantly&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:updates`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plant_placed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;plant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newPlant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Event Sourcing: Record for replay/analytics&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`game:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:events`&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plant_placed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plantType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Leaderboards: Update rankings&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard:plants_planted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plantsPlanted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 5. Analytics: Update global statistics&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter:plants_planted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pfadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hll:unique_players&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 6 different Redis capabilities in one operation!&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;h2&gt;
  
  
  &lt;strong&gt;Key Technical Achievements&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Architecture Innovation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero SQL databases&lt;/strong&gt; - Redis handles all data persistence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cache invalidation&lt;/strong&gt; - No cache layer because Redis IS the primary database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-driven design&lt;/strong&gt; - Pub/Sub eliminates all polling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete audit trails&lt;/strong&gt; - Streams provide event sourcing out of the box
### &lt;strong&gt;Performance Benefits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-millisecond operations&lt;/strong&gt; - All data operations in memory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero cache misses&lt;/strong&gt; - No cache layer means no cache invalidation complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal scalability&lt;/strong&gt; - Architecture ready for Redis Cluster deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory efficiency&lt;/strong&gt; - HyperLogLog and optimized data structures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;roduction Game Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistent progression&lt;/strong&gt; - Player statistics and achievements survive server restarts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live competitive rankings&lt;/strong&gt; - 5 different leaderboard categories updating in real-time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart user experience&lt;/strong&gt; - Auto-generated usernames, responsive design, health monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ** Deployment Ready**
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker support&lt;/strong&gt; - Single container and multi-container configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production logging&lt;/strong&gt; - Structured logging with multiple log levels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health monitoring&lt;/strong&gt; - Comprehensive health checks and metrics endpoints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete documentation&lt;/strong&gt; - Deployment guides, API documentation, development workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This Plants vs Zombies game demonstrates Redis as a complete, powerful, multi-model platform that can:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replace entire database stacks&lt;/strong&gt; - No PostgreSQL, MongoDB, or MySQL needed&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Provide real-time capabilities&lt;/strong&gt; - Built-in Pub/Sub eliminates message queues&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Handle complex analytics&lt;/strong&gt; - HyperLogLog, counters, and sorted sets for insights&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Scale to millions of users&lt;/strong&gt; - Ready for Redis Cluster horizontal scaling&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Deliver consistent sub-millisecond performance&lt;/strong&gt; - All operations in memory  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The game is fully functional, production-ready, and demonstrates Redis as the complete backend infrastructure for modern real-time applications.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>From Challenge to Comprehensive App, My Frontend Development Journey</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Sun, 27 Jul 2025 13:53:20 +0000</pubDate>
      <link>https://dev.to/lewisawe/from-challenge-to-comprehensive-app-my-frontend-development-journey-54dp</link>
      <guid>https://dev.to/lewisawe/from-challenge-to-comprehensive-app-my-frontend-development-journey-54dp</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend/axero"&gt;Frontend Challenge: Office Edition sponsored by Axero, Holistic Webdev: Office Space&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://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%2Fze6fav84b5j2mpfls2uz.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%2Fze6fav84b5j2mpfls2uz.png" alt="Nova Tech Dashboard" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a comprehensive &lt;strong&gt;Virtual Office Intranet&lt;/strong&gt; that transforms the traditional workplace experience into an engaging, interactive digital environment. The application simulates a complete office ecosystem with modern glass morphism design and real-time functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Interactive Office Desk&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%2Fa2626uu1gal3tvvbuhfm.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%2Fa2626uu1gal3tvvbuhfm.png" alt="Virtual Desk" width="759" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3x2 compact grid of interactive desk items (notes, coffee, plant, calendar, printer, paperclips)&lt;/li&gt;
&lt;li&gt;Each item has realistic interactions and state management&lt;/li&gt;
&lt;li&gt;Coffee levels, plant growth tracking, printer queue status&lt;/li&gt;
&lt;li&gt;Sticky notes system with realistic appearance and color coding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Enhanced Weather Widget&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%2F48916clnuhjbrk9911mp.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%2F48916clnuhjbrk9911mp.png" alt="Weather" width="512" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5-day forecast with detailed weather information&lt;/li&gt;
&lt;li&gt;Interactive controls and comprehensive stats&lt;/li&gt;
&lt;li&gt;Real-time updates and beautiful visual design&lt;/li&gt;
&lt;li&gt;Optimized to utilize space effectively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Team Management&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%2Fog34v88cstpkqq00mmte.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%2Fog34v88cstpkqq00mmte.png" alt="Teams" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live team member status and availability&lt;/li&gt;
&lt;li&gt;Skills tracking and action buttons&lt;/li&gt;
&lt;li&gt;Real-time status updates and interactions&lt;/li&gt;
&lt;li&gt;Professional profile cards with avatars&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Task &amp;amp; Project Management&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%2F1hz575syl9yj9g90rqlm.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%2F1hz575syl9yj9g90rqlm.png" alt="Task and Projects" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD operations for tasks with priority levels&lt;/li&gt;
&lt;li&gt;Progress tracking and completion statistics&lt;/li&gt;
&lt;li&gt;Interactive task cards with status indicators&lt;/li&gt;
&lt;li&gt;Pomodoro timer integration with circular progress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Meeting &amp;amp; Calendar System&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%2Fm4tut1bvtko8sqisw57x.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%2Fm4tut1bvtko8sqisw57x.png" alt="Meetings" width="499" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video meeting interface with participant grid&lt;/li&gt;
&lt;li&gt;Screen sharing options and chat system&lt;/li&gt;
&lt;li&gt;Meeting scheduling and management&lt;/li&gt;
&lt;li&gt;Calendar widget integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analytics Dashboard&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%2Fxdx8ukwgzqdim6r7m5g1.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%2Fxdx8ukwgzqdim6r7m5g1.png" alt="Analytics" width="499" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive charts and performance metrics&lt;/li&gt;
&lt;li&gt;Real-time data visualization&lt;/li&gt;
&lt;li&gt;Productivity insights and statistics&lt;/li&gt;
&lt;li&gt;Responsive chart interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Activity Feed&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%2Fai43q607v0pi3gp0vhmn.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%2Fai43q607v0pi3gp0vhmn.png" alt="Activity" width="754" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time activity notifications&lt;/li&gt;
&lt;li&gt;Team member actions and system updates&lt;/li&gt;
&lt;li&gt;Time-stamped entries with status indicators&lt;/li&gt;
&lt;li&gt;Comprehensive activity tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Comprehensive Toolbar&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%2F06laryjkus8zxkabv00y.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%2F06laryjkus8zxkabv00y.png" alt="ToolBars" width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email, calendar, HR portal, IT help desk&lt;/li&gt;
&lt;li&gt;Document management and analytics access&lt;/li&gt;
&lt;li&gt;Notes system and quick actions&lt;/li&gt;
&lt;li&gt;All features fully implemented and functional&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The full source code for NovaTech is available on GitHub. Feel free to explore, contribute, or fork the project: &lt;a href="https://github.com/lewisawe/NovaTech" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to see NovaTech in action? A live version is hosted on GitHub Pages for easy testing: &lt;a href="https://lewisawe.github.io/NovaTech/" rel="noopener noreferrer"&gt;Github Pages Live Link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Challenge
&lt;/h3&gt;

&lt;p&gt;The project started with a basic layout requirement but evolved into a comprehensive virtual office experience. The main challenges were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Creating Realistic Interactions&lt;/strong&gt;: Making desk items feel authentic with proper state management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design&lt;/strong&gt;: Ensuring the 3x2 desk items grid worked across all devices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Functionality&lt;/strong&gt;: Simulating live updates without a backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional UI/UX&lt;/strong&gt;: Achieving a modern, glass morphism design&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Development Process
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Foundation &amp;amp; Layout&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implemented basic HTML structure with semantic elements&lt;/li&gt;
&lt;li&gt;Created responsive grid system for office desk layout&lt;/li&gt;
&lt;li&gt;Established glass morphism design system with backdrop blur&lt;/li&gt;
&lt;li&gt;Set up proper color scheme and typography&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Interactive Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developed desk item interactions (coffee, notes, plant, etc.)&lt;/li&gt;
&lt;li&gt;Implemented modal system for detailed views&lt;/li&gt;
&lt;li&gt;Created sticky notes system with realistic appearance&lt;/li&gt;
&lt;li&gt;Added weather widget with comprehensive functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Data Integration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built comprehensive dummy data system (18KB of realistic data)&lt;/li&gt;
&lt;li&gt;Implemented API simulation with WebSocket functionality&lt;/li&gt;
&lt;li&gt;Created real-time update system for team status and activities&lt;/li&gt;
&lt;li&gt;Added proper error handling and fallback mechanisms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Advanced Features&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developed video meeting interface with participant grid&lt;/li&gt;
&lt;li&gt;Implemented task management with CRUD operations&lt;/li&gt;
&lt;li&gt;Created analytics dashboard with interactive charts&lt;/li&gt;
&lt;li&gt;Added Pomodoro timer with circular progress indicator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 5: Polish &amp;amp; Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed layout issues and responsive behavior&lt;/li&gt;
&lt;li&gt;Optimized desk items for 3x2 compact grid&lt;/li&gt;
&lt;li&gt;Enhanced activity feed with proper dummy data display&lt;/li&gt;
&lt;li&gt;Removed all test/debug files for clean production code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Decisions I'm Proud Of
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Glass Morphism Design System&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.desk-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.03&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&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;This creates a modern, professional appearance that's both beautiful and functional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Real-time Simulation Without Backend&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// WebSocket simulation for live updates&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;team_status_update&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;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sarah&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in_meeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Achieved real-time functionality using event simulation, making the app feel alive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Responsive 3x2 Grid System&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.desk-items&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&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;Perfect balance between desktop and mobile experiences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Comprehensive Data Architecture&lt;/strong&gt;&lt;br&gt;
Created 18KB of realistic dummy data covering team members, tasks, meetings, analytics, and activities - making the application feel like a real workplace tool.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CSS Grid Mastery&lt;/strong&gt;: Achieved complex responsive layouts with proper fallbacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management&lt;/strong&gt;: Implemented comprehensive state tracking without frameworks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI/UX Design&lt;/strong&gt;: Created professional interfaces with attention to detail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Optimization&lt;/strong&gt;: Balanced rich functionality with smooth performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Ensured proper focus management and semantic HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenges Overcome
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Layout Consistency&lt;/strong&gt;: Ensuring desk items matched weather widget proportions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Loading&lt;/strong&gt;: Preventing async data loading from breaking widget functionality
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Behavior&lt;/strong&gt;: Making 3x2 grid work across all screen sizes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Simulating live functionality without WebSocket server&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devchallenge</category>
      <category>frontendchallenge</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Digital Blueprinting with Kiro's Spec-Driven Development</title>
      <dc:creator>Lewis Sawe</dc:creator>
      <pubDate>Thu, 17 Jul 2025 11:14:26 +0000</pubDate>
      <link>https://dev.to/kirodotdev/digital-blueprinting-with-kiros-spec-driven-development-2fde</link>
      <guid>https://dev.to/kirodotdev/digital-blueprinting-with-kiros-spec-driven-development-2fde</guid>
      <description>&lt;p&gt;One of Kiro’s true power lies in its &lt;strong&gt;spec-driven development&lt;/strong&gt; approach, a structured methodology designed to transform vague ideas into code with clarity and consistency. We will walk through how to leverage core spec files that is &lt;code&gt;requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, and &lt;code&gt;tasks.md&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Spec-Driven Development?
&lt;/h3&gt;

&lt;p&gt;Traditional development often involves jumping straight into code, leading to scope Creep with requirements change mid development, misunderstandings with developers and stakeholders aren't on the same page, documentation Drift as Code evolves, but the docs don't. "Vibe Coding" AI generates code, but without a clear architectural vision.&lt;/p&gt;

&lt;p&gt;Kiro seeks to combats these issues by establishing a clear, AI parsable contract for your project from the outset. This allows it to act as a true copilot, ensuring your components align with your overall vision.&lt;/p&gt;

&lt;p&gt;I am going to demonstrate creating a Spec documents, through the creation of a simple stick fighting game.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Defining Your Vision with &lt;code&gt;requirements.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is where your project begins. This is your single source of truth for &lt;em&gt;what&lt;/em&gt; your system needs to do, leveraging this file to generate user stories, acceptance criteria, and a foundational understanding of your application.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;How to Implement It:&lt;/strong&gt;
&lt;/h4&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%2F50uspd3taeckvyvpsckc.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%2F50uspd3taeckvyvpsckc.png" alt="Getting Started" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Start with Core Gameplay:&lt;/strong&gt; Begin with a clear statement of what makes your fighting game unique.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;A web-based stickman fighting game where players control stick figure characters 
in combat scenarios. The game will feature simple controls, engaging combat mechanics, 
and smooth animations to provide an entertaining fighting experience directly in 
the browser.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Break Down into User Stories (EARS Notation Recommended):&lt;/strong&gt; Use the EARS (Easy to Understand, Atomic, Readable, Specific) notation or a similar structured format to define individual features from a user's perspective. Include clear acceptance criteria.&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="gu"&gt;## Requirements&lt;/span&gt;

&lt;span class="gu"&gt;### Requirement 1&lt;/span&gt;

&lt;span class="gs"&gt;**User Story:**&lt;/span&gt; As a player, I want to control a stickman character with keyboard inputs, so that I can move and perform actions in the fighting arena.

&lt;span class="gu"&gt;#### Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; WHEN the player presses arrow keys THEN the stickman SHALL move left, right, jump, or crouch accordingly
&lt;span class="p"&gt;2.&lt;/span&gt; WHEN the player presses attack keys THEN the stickman SHALL perform punch or kick animations
&lt;span class="p"&gt;3.&lt;/span&gt; WHEN the player presses block key THEN the stickman SHALL enter defensive stance
&lt;span class="p"&gt;4.&lt;/span&gt; WHEN multiple keys are pressed simultaneously THEN the system SHALL handle combination moves appropriately

&lt;span class="gu"&gt;### Requirement 2&lt;/span&gt;

&lt;span class="gs"&gt;**User Story:**&lt;/span&gt; As a player, I want to engage in combat with an opponent, so that I can experience competitive fighting gameplay.

&lt;span class="gu"&gt;#### Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; WHEN two stickman characters are in proximity THEN attacks SHALL be able to connect and deal damage
&lt;span class="p"&gt;2.&lt;/span&gt; WHEN a character's health reaches zero THEN the system SHALL declare the opponent as winner
&lt;span class="p"&gt;3.&lt;/span&gt; WHEN an attack connects THEN the system SHALL provide visual feedback and reduce target's health
&lt;span class="p"&gt;4.&lt;/span&gt; WHEN characters collide THEN the system SHALL handle collision detection accurately

&lt;span class="gu"&gt;### Requirement 3&lt;/span&gt;

&lt;span class="gs"&gt;**User Story:**&lt;/span&gt; As a player, I want to see smooth animations and visual effects, so that the fighting feels responsive and engaging.

&lt;span class="gu"&gt;#### Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; WHEN a character performs any action THEN the system SHALL display appropriate stick figure animations
&lt;span class="p"&gt;2.&lt;/span&gt; WHEN attacks connect THEN the system SHALL show impact effects or particle effects
&lt;span class="p"&gt;3.&lt;/span&gt; WHEN characters move THEN the animations SHALL be fluid at 60 FPS or higher
&lt;span class="p"&gt;4.&lt;/span&gt; WHEN the game runs THEN all animations SHALL be synchronized with game logic

&lt;span class="gu"&gt;### Requirement 4&lt;/span&gt;

&lt;span class="gs"&gt;**User Story:**&lt;/span&gt; As a player, I want a simple game interface, so that I can easily understand the game state and controls.

&lt;span class="gu"&gt;#### Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; WHEN the game loads THEN the system SHALL display health bars for both players
&lt;span class="p"&gt;2.&lt;/span&gt; WHEN the game is in progress THEN the system SHALL show current round information
&lt;span class="p"&gt;3.&lt;/span&gt; WHEN the game ends THEN the system SHALL display winner announcement and restart option
&lt;span class="p"&gt;4.&lt;/span&gt; WHEN the player needs help THEN the system SHALL provide accessible control instructions

&lt;span class="gu"&gt;### Requirement 5&lt;/span&gt;

&lt;span class="gs"&gt;**User Story:**&lt;/span&gt; As a player, I want the game to work reliably in my web browser, so that I can play without technical issues.

&lt;span class="gu"&gt;#### Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; WHEN the game loads in a modern web browser THEN it SHALL run without requiring additional plugins
&lt;span class="p"&gt;2.&lt;/span&gt; WHEN the browser window is resized THEN the game SHALL maintain proper aspect ratio and playability
&lt;span class="p"&gt;3.&lt;/span&gt; WHEN the game runs for extended periods THEN performance SHALL remain stable without memory leaks
&lt;span class="p"&gt;4.&lt;/span&gt; WHEN network connectivity is poor THEN the game SHALL still function as a local experience
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Clarify Technical Requirements:&lt;/strong&gt; Include platform compatibility and performance targets.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Technical Requirements&lt;/span&gt;

&lt;span class="gu"&gt;### Platform Support&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Work on modern web browsers (Chrome, Firefox, Safari, Edge)
&lt;span class="p"&gt;2.&lt;/span&gt; Responsive design that adapts to different screen sizes
&lt;span class="p"&gt;3.&lt;/span&gt; Mobile device support

&lt;span class="gu"&gt;### Performance&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Maintain 60 FPS on mid-range devices
&lt;span class="p"&gt;2.&lt;/span&gt; Optimize animations and physics calculations
&lt;span class="p"&gt;3.&lt;/span&gt; Efficient memory usage

&lt;span class="gu"&gt;### Technology Stack&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; HTML5, CSS3, and JavaScript
&lt;span class="p"&gt;2.&lt;/span&gt; Canvas or WebGL for rendering
&lt;span class="p"&gt;3.&lt;/span&gt; Potential use of game frameworks (optional)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Architecting Your Game with &lt;code&gt;design.md&lt;/code&gt;
&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%2Fyz0azi5zoer9oijzshep.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%2Fyz0azi5zoer9oijzshep.png" alt="Design" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With clear requirements, we move into the design phase. The &lt;code&gt;design.md&lt;/code&gt; file (or a collection of design files within a &lt;code&gt;design/&lt;/code&gt; directory) outlines &lt;em&gt;how&lt;/em&gt; your system will meet those requirements. This is where you define architecture, data models, API schemas, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Implement It:&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;High-Level Architecture:&lt;/strong&gt; Describe the overall system components
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Design Document&lt;/span&gt;

&lt;span class="gu"&gt;## Overview&lt;/span&gt;

The stickman fighting game will be built as a client-side web application using HTML5 Canvas and JavaScript. The architecture follows a component-based game engine pattern with clear separation between rendering, game logic, input handling, and animation systems. The game will use a fixed timestep game loop for consistent physics and animation, with interpolation for smooth 60 FPS rendering.

&lt;span class="gu"&gt;## Architecture&lt;/span&gt;

&lt;span class="gu"&gt;### Core Architecture Pattern&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Entity-Component System (ECS)**&lt;/span&gt;: Characters and game objects are entities with components for position, health, animation, collision, etc.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Game Loop**&lt;/span&gt;: Fixed timestep update loop with variable timestep rendering
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**State Management**&lt;/span&gt;: Finite state machine for game states (menu, playing, paused, game over)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Event-Driven Input**&lt;/span&gt;: Keyboard input system with event queuing and combination detection

&lt;span class="gu"&gt;### Technology Stack&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Rendering**&lt;/span&gt;: HTML5 Canvas 2D API for graphics and animations
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Language**&lt;/span&gt;: Vanilla JavaScript (ES6+) for maximum browser compatibility
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Build**&lt;/span&gt;: No build system required - direct HTML/JS/CSS files
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Animation**&lt;/span&gt;: Custom sprite-based animation system with frame interpolation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Components and Interfaces: Characters and game objects are entities with components for position, health, animation, collision, etc
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Components and Interfaces&lt;/span&gt;

&lt;span class="gu"&gt;### Game Engine Core&lt;/span&gt;

&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;
&lt;/span&gt;
javascript
// Main game engine interface
class GameEngine {
  constructor(canvas)
  start()
  stop()
  update(deltaTime)
  render(interpolation)
}

// Character entity with component composition
class Character {
  constructor(x, y, playerIndex)
  // Components
  position: PositionComponent
  health: HealthComponent
  animation: AnimationComponent
  collision: CollisionComponent
  input: InputComponent
}

// Character states for animation and behavior
enum CharacterState {
  IDLE, WALKING, JUMPING, CROUCHING, 
  PUNCHING, KICKING, BLOCKING, HURT, DEAD
}

class InputManager {
  constructor()
  bindKeys(playerIndex, keyMapping)
  getInputState(playerIndex)
  handleKeyDown(event)
  handleKeyUp(event)
}

// Input mapping for two players
const PLAYER_CONTROLS = {
  PLAYER1: { left: 'ArrowLeft', right: 'ArrowRight', up: 'ArrowUp', down: 'ArrowDown', punch: 'KeyZ', kick: 'KeyX', block: 'KeyC' },
  PLAYER2: { left: 'KeyA', right: 'KeyD', up: 'KeyW', down: 'KeyS', punch: 'KeyJ', kick: 'KeyK', block: 'KeyL' }
}

class AnimationManager {
  constructor()
  createAnimation(name, frames, duration, loop)
  playAnimation(character, animationName)
  update(deltaTime)
}

class SpriteRenderer {
  constructor(canvas)
  drawStickman(character, interpolation)
  drawUI(gameState)
  drawEffects(effects)
}


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Error handling, Testing strategy and Implementation Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
markdown

## Error Handling

### Input Error Handling
- **Invalid Key Combinations**: Ignore conflicting inputs (e.g., left + right simultaneously)
- **Rapid Key Presses**: Implement debouncing for attack inputs to prevent spam
- **Browser Compatibility**: Feature detection for Canvas API and fallback messaging

### Game Logic Error Handling
- **Animation Errors**: Default to idle animation if animation file missing or corrupted
- **Collision Edge Cases**: Boundary checking to prevent characters from moving outside arena
- **Performance Degradation**: Frame rate monitoring with automatic quality reduction if needed

### Rendering Error Handling
- **Canvas Context Loss**: Detect context loss and reinitialize rendering system
- **Memory Leaks**: Proper cleanup of animation frames and event listeners
- **Browser Resize**: Responsive canvas sizing with aspect ratio preservation

## Testing Strategy

### Unit Testing
- **Character Movement**: Test position updates, boundary constraints, and state transitions
- **Collision Detection**: Verify hitbox calculations and attack/defense interactions
- **Animation System**: Test frame progression, loop behavior, and state synchronization
- **Input Processing**: Validate key mapping, combination detection, and player separation

### Integration Testing
- **Game Loop**: Test update/render cycle timing and state consistency
- **Character Interactions**: Verify combat mechanics, health reduction, and win conditions
- **UI Integration**: Test health bar updates, game state displays, and user feedback

### Performance Testing
- **Frame Rate Consistency**: Monitor FPS under various load conditions
- **Memory Usage**: Track memory allocation and garbage collection patterns
- **Browser Compatibility**: Test across Chrome, Firefox, Safari, and Edge

### Visual Testing
- **Animation Smoothness**: Verify 60 FPS rendering and frame interpolation
- **Collision Feedback**: Test visual effects for hits, blocks, and impacts
- **UI Responsiveness**: Ensure interface elements update correctly with game state


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Implementation Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  File Structure
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
markdown
stickman-fighting-game/
├── index.html
├── css/
│   └── game.css
├── js/
│   ├── engine/
│   │   ├── GameEngine.js
│   │   ├── InputManager.js
│   │   └── AnimationManager.js
│   ├── entities/
│   │   ├── Character.js
│   │   └── Effect.js
│   ├── systems/
│   │   ├── PhysicsSystem.js
│   │   ├── CollisionSystem.js
│   │   └── RenderSystem.js
│   └── main.js
└── assets/
    └── sounds/ (optional for future enhancement)


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Rendering Pipeline
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Canvas&lt;/strong&gt;: Clear previous frame&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: Draw arena background&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Characters&lt;/strong&gt;: Render stickman sprites with current animation frame&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effects&lt;/strong&gt;: Draw particle effects and impact animations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UI&lt;/strong&gt;: Overlay health bars, round info, and game state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt;: Optional collision box visualization&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 3: Executing the Plan with &lt;code&gt;tasks.md&lt;/code&gt;
&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%2Fe5teaqwsdf336nq0xjpr.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%2Fe5teaqwsdf336nq0xjpr.png" alt="tasks" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where Kiro breaks down the design into actionable, atomic steps for implementation. &lt;code&gt;tasks.md&lt;/code&gt; typically isn't something you write from scratch, which it then generates it based on your &lt;code&gt;requirements.md&lt;/code&gt; and &lt;code&gt;design.md&lt;/code&gt;. Your role here is to review, refine, and track progress.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;How to Leverage It:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Review Generated Tasks:&lt;/strong&gt; Once you've created requirements and design documents, break them down into specific tasks:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
markdown
# Implementation Plan

- [ ] 1. Set up project structure and core HTML/CSS foundation
  - Create index.html with canvas element and basic page structure
  - Create game.css with responsive canvas styling and UI layout
  - Set up file directory structure for organized code modules
  - _Requirements: 5.1, 5.2_

- [ ] 2. Implement core game engine and loop system
  - Create GameEngine.js with fixed timestep game loop and requestAnimationFrame
  - Implement game state management (MENU, PLAYING, PAUSED, GAME_OVER)
  - Add canvas context initialization and error handling for context loss
  - Write unit tests for game loop timing and state transitions
  - _Requirements: 5.1, 5.3, 3.3_

- [ ] 3. Build input management system
  - Create InputManager.js with keyboard event handling and key mapping
  - Implement two-player control schemes with configurable key bindings
  - Add combination key detection and input debouncing for attacks
  - Write unit tests for input processing and player separation
  - _Requirements: 1.1, 1.2, 1.3, 1.4_

- [ ] 4. Create character entity and component system
  - Implement Character.js with position, health, and state components
  - Create character state enumeration (IDLE, WALKING, JUMPING, etc.)
  - Add character initialization with starting positions and properties
  - Write unit tests for character creation and component management
  - _Requirements: 1.1, 2.2_

- [ ] 5. Implement basic character movement and physics
  - Add movement logic for left/right walking and jumping mechanics
  - Implement gravity system and ground collision detection
  - Create boundary constraints to keep characters within arena
  - Write unit tests for movement calculations and boundary checking
  - _Requirements: 1.1, 5.2_


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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Starting your Implementation Plan
&lt;/h4&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%2Fr5fzpz2p7bdylpwxrm7y.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%2Fr5fzpz2p7bdylpwxrm7y.png" alt="Implementation" width="707" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of Synchronization: Living Documentation
&lt;/h3&gt;

&lt;p&gt;One of Kiro's most powerful features is its ability to keep these specification files in sync with your codebase.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Changes in Code -&amp;gt; Updates in Specs:&lt;/strong&gt; If you decide to change an API endpoint directly in your code, then it prompts you to update &lt;code&gt;design.md&lt;/code&gt; accordingly, or even suggest the change automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Changes in Specs -&amp;gt; Updates in Code:&lt;/strong&gt; If you modify a data model in &lt;code&gt;design.md&lt;/code&gt;, it then can suggest or even apply the necessary code changes (e.g., updating TypeScript interfaces, DynamoDB table definitions).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "living documentation" ensures that your specifications always reflect the current state of your application, reducing maintenance overhead and eliminating the classic problem of outdated documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embracing Spec-Driven Workflow
&lt;/h3&gt;

&lt;p&gt;Mastering &lt;code&gt;requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, and &lt;code&gt;tasks.md&lt;/code&gt; is key to harnessing the full potential of Kiro. By embracing this structured, spec-driven workflow, you'll benefit from Increased Clarity where everyone is aligned on what's being built and how. Reduced Errors you can validate code against the specs, catching inconsistencies early. Faster Development of accurate code and infrastructure from precise instructions, and your documentation stays evergreen, making future changes easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join me on this journey as I create my stick game, step by step, spec by spec, and discover the benefits of intentional, efficient development with Kiro.&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%2F718ph6fs0b4j6vsymyod.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%2F718ph6fs0b4j6vsymyod.png" alt="Stick Fight" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets Connect - Lewis Sawe: &lt;a href="https://www.linkedin.com/in/lewisawe/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Buy me &lt;a href="https://buymeacoffee.com/lewisawe" rel="noopener noreferrer"&gt;coffee&lt;/a&gt; ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>kiro</category>
      <category>aws</category>
      <category>genai</category>
    </item>
  </channel>
</rss>
