<?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: Atul Anand</title>
    <description>The latest articles on DEV Community by Atul Anand (@ibatulanand).</description>
    <link>https://dev.to/ibatulanand</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%2F1327550%2Fd27755cf-ea92-4a85-9243-e718d9d361bd.png</url>
      <title>DEV Community: Atul Anand</title>
      <link>https://dev.to/ibatulanand</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ibatulanand"/>
    <language>en</language>
    <item>
      <title>Build Production-ready AI Agents with AWS Bedrock &amp; Agentcore</title>
      <dc:creator>Atul Anand</dc:creator>
      <pubDate>Mon, 26 Jan 2026 12:31:03 +0000</pubDate>
      <link>https://dev.to/aws-builders/build-production-ready-ai-agents-with-aws-bedrock-agentcore-13kk</link>
      <guid>https://dev.to/aws-builders/build-production-ready-ai-agents-with-aws-bedrock-agentcore-13kk</guid>
      <description>&lt;p&gt;So you've heard about AI agents, right? They're everywhere now… automating workflows, answering customer queries, and even planning product launches.&lt;/p&gt;

&lt;p&gt;But here's the thing: building one that actually works in production is a whole different game compared to throwing together a ChatGPT wrapper.&lt;/p&gt;

&lt;p&gt;I recently built an &lt;strong&gt;&lt;em&gt;"AI-powered Product Hunt launch assistant"&lt;/em&gt;&lt;/strong&gt; during the &lt;strong&gt;AWS AI Agent Hackathon&lt;/strong&gt; at AWS Startup Loft, Tokyo. And honestly? It taught me a ton about what it takes to build production-ready AI agents on AWS.&lt;/p&gt;

&lt;p&gt;In this article, I'll try to walk you through the process of how to build on AWS, think about the architecture, the tools, and share the lessons that I learnt, so you can build your own AI agent-based projects without the trial-and-error pain.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The hackathon crew at AWS AI Agent Hackathon&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwzo7xnjct8qx644zq9v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwzo7xnjct8qx644zq9v.jpg" alt="The hackathon crew at AWS AI Agent Hackathon" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What We're Building: The Product Hunt Launch Assistant
&lt;/h2&gt;

&lt;p&gt;Before diving into the tech, let me give you context. The &lt;strong&gt;Product Hunt Launch Assistant&lt;/strong&gt; is an AI agent that helps entrepreneurs plan and execute their &lt;a href="https://www.producthunt.com/" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; launches. It can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate comprehensive launch timelines with task dependencies&lt;/li&gt;
&lt;li&gt;Create marketing assets (taglines, tweets, descriptions)&lt;/li&gt;
&lt;li&gt;Research successful launches in our category&lt;/li&gt;
&lt;li&gt;Recommend hunters and outreach strategies&lt;/li&gt;
&lt;li&gt;Remember our product context across sessions (yes, it has memory!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The interface to prepare your project info to launch&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0k3ntyzzegqp0cr7rfv.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%2Fh0k3ntyzzegqp0cr7rfv.png" alt="The interface to prepare your project info to launch" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The chat interface with real-time streaming responses&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle6h29qf4y5nzicuzvmg.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%2Fle6h29qf4y5nzicuzvmg.png" alt="The chat interface with real-time streaming responses" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cool part? All of this runs on &lt;strong&gt;AWS Bedrock&lt;/strong&gt; using the &lt;strong&gt;Strands Agents SDK&lt;/strong&gt; and &lt;strong&gt;AgentCore Memory&lt;/strong&gt;. Let me break down how it all works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you wanna follow along or check out the code, head over to &lt;a href="https://github.com/ibatulanandjp/product-hunt-launch-assistant" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The AWS AI Agent Stack
&lt;/h2&gt;

&lt;p&gt;The core components that comprise the stack are going to be:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Bedrock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed AI service that gives us access to foundation models like Claude, Amazon Nova, Llama, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strands Agents SDK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS's open-source framework for building AI agents with Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AgentCore Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless execution environment for our agents with session isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AgentCore Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Persistent memory system for maintaining context across sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AgentCore Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connects our agents to APIs, Lambda functions, and MCP servers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  AI Agent Architecture
&lt;/h2&gt;

&lt;p&gt;Let's look at how the Product Hunt Launch Assistant is structured:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full system architecture&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0zi342kf4aih1yittoa.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%2Fm0zi342kf4aih1yittoa.png" alt="Full system architecture" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  1. The Agent Layer (Strands SDK)
&lt;/h3&gt;

&lt;p&gt;The heart of the application is the &lt;code&gt;ProductHuntLaunchAgent&lt;/code&gt; class, where we create the agent.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductHuntLaunchAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&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;region_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&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="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Initialize the Bedrock model (Claude 3.5 Haiku)
&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;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic.claude-3-5-haiku-20241022-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# Enable streaming
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Create the agent with Product Hunt tools and memory hooks
&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;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;generate_launch_timeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;generate_marketing_assets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;research_top_launches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;system_prompt&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;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;hooks&lt;/span&gt;&lt;span class="o"&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;memory_hooks&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;What I love about &lt;a href="https://strandsagents.com/latest/" rel="noopener noreferrer"&gt;Strands&lt;/a&gt; is how &lt;strong&gt;minimal&lt;/strong&gt; the code is. You give it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A model (Claude via Bedrock in this case)&lt;/li&gt;
&lt;li&gt;A list of tools the agent can use&lt;/li&gt;
&lt;li&gt;A system prompt with domain expertise&lt;/li&gt;
&lt;li&gt;Optional hooks for things like memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! The framework handles all the reasoning, tool selection, and response generation. No complex prompt chains or hardcoded workflows.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Custom Tools with the @tool Decorator
&lt;/h3&gt;

&lt;p&gt;Tools are where our agent gets its superpowers. Strands makes it dead simple with the &lt;code&gt;@tool&lt;/code&gt; decorator:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_launch_timeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;product_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;launch_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;additional_notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Generate a comprehensive launch timeline and checklist for Product Hunt launch.

    Args:
        product_name: Name of the product to launch
        product_type: Type of product (SaaS, Mobile App, Chrome Extension, etc.)
        launch_date: Target launch date (e.g., &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next Tuesday&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;December 15, 2024&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
        additional_notes: Any additional requirements or constraints
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse launch date, calculate timeline, return structured data
&lt;/span&gt;    &lt;span class="n"&gt;parsed_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_launch_date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;launch_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;days_until_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_timeline_days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;timeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_timeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days_until_launch&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;timeline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_days&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;days_until_launch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;launch_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;format_date_for_display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed_date&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;key_milestones&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;extract_milestones&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The docstring is super important here!!! as it tells the AI model what the tool does and when to use it. The model reads this and decides autonomously when to invoke each tool based on user queries.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI-generated launch timeline with detailed task breakdown&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb6xw8yv9nbt281boz7a.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%2Fwb6xw8yv9nbt281boz7a.png" alt="AI-generated launch timeline with detailed task breakdown" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  3. The Memory System (AgentCore Memory)
&lt;/h3&gt;

&lt;p&gt;This is where things get interesting. Most AI chatbots are stateless. They forget everything after each conversation. But for a SaaS product, we need &lt;strong&gt;persistence&lt;/strong&gt;. We need the agent to remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What product is the user launching&lt;/li&gt;
&lt;li&gt;Their preferences and communication style&lt;/li&gt;
&lt;li&gt;Previous recommendations and decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AgentCore Memory solves this with two types of memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short-term memory&lt;/strong&gt;: Keeps track of the current conversation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term memory&lt;/strong&gt;: Stores key insights across multiple sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how I implemented memory hooks with Strands:&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.memory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MemoryClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.hooks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HookProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HookRegistry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessageAddedEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AfterInvocationEvent&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductHuntMemoryHooks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HookProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&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;memory_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MemoryClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actor_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory_id&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&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;actor_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actor_id&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;session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_product_context&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageAddedEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Retrieve product and user context BEFORE processing the query.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;user_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Get relevant memories from both namespaces
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;context_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ow"&gt;in&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;namespaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;memories&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve_memories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;memory_id&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;memory_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actorId&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;actor_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;top_k&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="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# Inject context into the user's message
&lt;/span&gt;            &lt;span class="c1"&gt;# ...
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_launch_interaction&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AfterInvocationEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Save the interaction AFTER the agent responds.&lt;/span&gt;&lt;span class="sh"&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;memory_id&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;memory_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;actor_id&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;actor_id&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;self&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="n"&gt;messages&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="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USER&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;agent_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;ASSISTANT&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key insight here is the &lt;strong&gt;hook system&lt;/strong&gt;. Before each message is processed, we retrieve relevant memories and inject them as context. After the agent responds, we save the interaction for future reference.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The agent remembering product context across sessions&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2r4f01663eer87kwjib2.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%2F2r4f01663eer87kwjib2.png" alt="The agent remembering product context across sessions" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I set up two memory strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;USER_PREFERENCE&lt;/strong&gt;: Stores user preferences, communication style, strategic approaches, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEMANTIC&lt;/strong&gt;: Stores factual information about products, launch strategies, recommendations, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The memories expire after 90 days (configurable), and the memory ID is stored in AWS SSM Parameter Store for persistence.&lt;/p&gt;


&lt;h2&gt;
  
  
  Building the API Layer
&lt;/h2&gt;

&lt;p&gt;For the web interface, I used FastAPI with Server-Sent Events (SSE) for streaming responses:&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;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.responses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StreamingResponse&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;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/chat-stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ChatRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;event_generator&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_or_create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&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;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&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;chat_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: [DONE]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;StreamingResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;event_generator&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;media_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/event-stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The streaming experience is crucial for UX. Nobody wants to stare at a loading spinner for 10 seconds.&lt;/p&gt;




&lt;p&gt;And, that's actually it!&lt;/p&gt;

&lt;p&gt;It's that simple and straightforward.&lt;/p&gt;

&lt;p&gt;You can simply add a UI to the backend (or vibe code it), and you've built a fully functional, scalable, and production-ready SaaS for yourself.&lt;/p&gt;

&lt;p&gt;But, to truly make it production-ready, there are a few things that I'd do differently.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1. Start with AgentCore Runtime for Production
&lt;/h3&gt;

&lt;p&gt;When I built this, I ran the agent locally. For production, I'd use &lt;strong&gt;AgentCore Runtime&lt;/strong&gt; from day one. It gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session isolation (no state leaking between users)&lt;/li&gt;
&lt;li&gt;8-hour execution windows (for long-running tasks)&lt;/li&gt;
&lt;li&gt;Pay-per-use pricing&lt;/li&gt;
&lt;li&gt;Built-in security with identity management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Use Infrastructure as Code
&lt;/h3&gt;

&lt;p&gt;The hackathon version has no Terraform/CDK. Big mistake for production. I'd always go with IaC to keep things consistent and manageable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory resources defined in CloudFormation&lt;/li&gt;
&lt;li&gt;Lambda functions for tools (if needed)&lt;/li&gt;
&lt;li&gt;Proper IAM roles and policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probably wanna check this &lt;a href="https://aws.amazon.com/blogs/machine-learning/amazon-bedrock-announces-general-availability-of-multi-agent-collaboration" rel="noopener noreferrer"&gt;official AWS article&lt;/a&gt;, which outlines building AI Agents with CloudFormation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build Modular Tools
&lt;/h3&gt;

&lt;p&gt;My tools are pretty monolithic. In hindsight, I'd break them into smaller, composable pieces. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;parse_date&lt;/code&gt; tool&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;calculate_timeline&lt;/code&gt; tool&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;format_output&lt;/code&gt; tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the agent more flexible and easier to test.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Plan for Multi-Agent Systems
&lt;/h3&gt;

&lt;p&gt;The Product Hunt assistant is a single agent. But as your SaaS grows, you'll want multiple agents working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;research agent&lt;/strong&gt; that finds competitor data&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;content agent&lt;/strong&gt; that writes marketing copy&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;scheduling agent&lt;/strong&gt; that optimizes launch timing&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;orchestrator agent&lt;/strong&gt; that coordinates everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, apart from these, some best practices that I'd put into place would be to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collect ground truth data&lt;/strong&gt;: building a dataset of user queries and expected responses for testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Bedrock Guardrails&lt;/strong&gt;: adding safety rails to prevent harmful outputs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor with AgentCore Observability&lt;/strong&gt;: integrating with CloudWatch, Datadog, or LangSmith for clear insights and observability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test tool selection&lt;/strong&gt;: making sure the agent picks the right tool for each query&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Alright, that's it! If you've made it this far, you now know more about building AI agents on AWS than most developers out there. The stack is still evolving fast, but the fundamentals of tools, memory, and agents aren't going anywhere.&lt;/p&gt;

&lt;p&gt;If you wanna try it out yourself, find the code for the assistant on &lt;a href="https://github.com/ibatulanandjp/product-hunt-launch-assistant" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So go ahead, clone the repo, break things, and build something cool. And hey, if you end up launching on Product Hunt using this assistant, let me know, I'd love to see what you ship!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
    </item>
    <item>
      <title>Save money on AWS by getting daily cost notifications for FREE!</title>
      <dc:creator>Atul Anand</dc:creator>
      <pubDate>Mon, 20 Jan 2025 16:32:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/save-money-on-aws-by-getting-daily-cost-notifications-for-free-3kce</link>
      <guid>https://dev.to/aws-builders/save-money-on-aws-by-getting-daily-cost-notifications-for-free-3kce</guid>
      <description>&lt;p&gt;Are you a solo using an AWS account, a startup building on AWS, or a big company with multiple AWS Organizations having a multi-account setup? Do you also find it challenging to track billing and manage costs across all the accounts?&lt;/p&gt;

&lt;p&gt;In my 5+ years of &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; journey, I have seen many organizations struggle with the complexity of tracking and managing their cloud expenses.&lt;/p&gt;




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

&lt;p&gt;One of the most common challenges organizations face using AWS is the lack of real-time visibility into their cloud expenses.&lt;/p&gt;

&lt;p&gt;The critical complexity is in the early identification of outliers in case of cost spikes, or identification of unnecessary costs because of dormant resources. The lack of visibility and timely insight into daily expenses can lead to unexpected bills and budget overruns, causing significant stress and financial strain.&lt;/p&gt;

&lt;p&gt;Although we do have the provisions of &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html" rel="noopener noreferrer"&gt;Budget Alerts&lt;/a&gt;, it’s hard to predict daily cost initially and the range varies quite a lot based on usage. Moreover, it’s such a daunting and time-consuming task to keep monitoring daily costs using &lt;a href="https://aws.amazon.com/aws-cost-management/aws-cost-explorer/" rel="noopener noreferrer"&gt;AWS Cost Explorer&lt;/a&gt; daily.&lt;/p&gt;

&lt;p&gt;Wouldn’t it be nice to get a simple notification that tells you daily cost by services and by accounts, and save the hassle of jumping across AWS accounts billing dashboards?&lt;/p&gt;

&lt;p&gt;So for this, I bring you a serverless solution called ‘&lt;a href="https://github.com/ibatulanandjp/aws-cost-report" rel="noopener noreferrer"&gt;AWS Cost Report&lt;/a&gt;’!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: AWS Cost Report
&lt;/h2&gt;

&lt;p&gt;The AWS Cost Report is an open-source project that addresses this challenge by automating the collection and reporting of AWS cost data.&lt;/p&gt;

&lt;p&gt;By leveraging serverless technologies, this solution provides a seamless and efficient way to monitor daily costs and receive notifications in your preferred communication platform (Slack or Microsoft Teams).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Access it on Github: &lt;a href="https://github.com/ibatulanandjp/aws-cost-report" rel="noopener noreferrer"&gt;https://github.com/ibatulanandjp/aws-cost-report&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated Cost Data Collection&lt;/strong&gt;: The solution fetches daily cost data from AWS Cost Explorer, eliminating the need for manual data retrieval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily Notifications&lt;/strong&gt;: Receive daily cost reports in Slack or Microsoft Teams, providing timely insights into your cloud expenses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Account Support&lt;/strong&gt;: The solution can be deployed in a master account to aggregate costs from multiple child accounts, providing a consolidated view of expenses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable Configuration&lt;/strong&gt;: Easily configure the solution to suit your needs, including account IDs, preferred currency, timezone offset, and notification platform.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Technical Architecture
&lt;/h2&gt;

&lt;p&gt;The AWS Cost Report project is built using AWS Lambda and AWS CDK, ensuring a scalable and cost-effective solution. Let’s dive into the technical architecture of the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Multi-Account
&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%2F6z9rxd2nv7ecda8b242d.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%2F6z9rxd2nv7ecda8b242d.png" alt="Multi-account/Organization-wide architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This deployment architecture can be used where you have one or multiple departments or organizational units managing their own AWS Organization, then you can deploy it at the Master Account level. The system will aggregate the account-wise cost and send notifications to the subscribed channel.&lt;/p&gt;

&lt;h4&gt;
  
  
  Standalone Account
&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%2F14giv3r6qw61q9f59b9q.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%2F14giv3r6qw61q9f59b9q.png" alt="Standalone account architecture" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This setup is useful to deploy to a single account and get notifications daily in the subscribed channel specific to that account only.&lt;/p&gt;




&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS Lambda Function
&lt;/h3&gt;

&lt;p&gt;The core functionality of the application is implemented within an &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; function. This function performs the following tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch Cost Data: The function uses the &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/ce-api.html" rel="noopener noreferrer"&gt;AWS Cost Explorer API&lt;/a&gt; to fetch daily cost data for the specified account(s).&lt;/li&gt;
&lt;li&gt;Process Data: The fetched data is processed to calculate costs in the preferred currency and format the information for notification.&lt;/li&gt;
&lt;li&gt;Send Notifications: The function constructs a notification message and sends it to the configured &lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; or &lt;a href="https://www.microsoft.com/en-us/microsoft-teams/group-chat-software" rel="noopener noreferrer"&gt;Microsoft Teams&lt;/a&gt; channel using webhook URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AWS CloudWatch Events Rule
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/cloudwatch-events.html" rel="noopener noreferrer"&gt;CloudWatch Events&lt;/a&gt; rule is scheduled to trigger the Lambda function daily at a specific time (e.g., 8 am JST or 23:00 UTC). When triggered, the rule invokes the Lambda function to collect and process the cost data.&lt;/p&gt;

&lt;h3&gt;
  
  
  External Notification Platforms (Slack or Microsoft Teams)
&lt;/h3&gt;

&lt;p&gt;The application sends notifications to the specified Slack or Microsoft Teams channel using webhook URLs configured in the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Daily Notification Output
&lt;/h2&gt;

&lt;p&gt;Once configured and deployed in the AWS account(s), you’ll start receiving daily notifications for the costs incurred sorted by service.&lt;/p&gt;

&lt;p&gt;The notification summarizes your AWS costs, helping you stay informed about your cloud expenses. Here’s an example of how the notification will look in Slack and Microsoft Teams:&lt;/p&gt;

&lt;h3&gt;
  
  
  Slack Notification
&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%2F2a2a2n7eywg2nqruas10.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%2F2a2a2n7eywg2nqruas10.png" alt="Slack notification" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Microsoft Teams Notification
&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%2F6yf64pe4r1m3lw8a109o.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%2F6yf64pe4r1m3lw8a109o.png" alt="Microsoft Team notification" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The notification message includes the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Date: The date for which the cost data is reported.&lt;/li&gt;
&lt;li&gt;Account: Account ID and alias name set for that account.&lt;/li&gt;
&lt;li&gt;Total Cost: The total cost (in your preferred currency) incurred for the specified accounts on the given date.&lt;/li&gt;
&lt;li&gt;Cost by Service: A breakdown of the expenses by AWS service, showing top services and how they contributed to the total cost.&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;So, just go and clone the Github Repo now 🚀: &lt;a href="https://github.com/ibatulanandjp/aws-cost-report.git" rel="noopener noreferrer"&gt;https://github.com/ibatulanandjp/aws-cost-report.git&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hope this helps manage your AWS costs and would be happy to accept contributions on the repo, to make it more robust, and allow it to cater notifications to different platforms.&lt;/p&gt;

&lt;p&gt;If you are into AWS, I recommend your next read to be: &lt;br&gt;
&lt;a href="https://dev.to/aws-builders/switch-between-aws-accounts-in-your-cli-like-never-before-l9b"&gt;Switch between AWS Accounts in your CLI like never before&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://aws.plainenglish.io/save-money-on-aws-by-getting-daily-cost-notifications-for-free-d892eb121c7f" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>opensource</category>
      <category>serverless</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Switch between AWS accounts in your CLI like never before!</title>
      <dc:creator>Atul Anand</dc:creator>
      <pubDate>Sat, 05 Oct 2024 13:23:43 +0000</pubDate>
      <link>https://dev.to/aws-builders/switch-between-aws-accounts-in-your-cli-like-never-before-l9b</link>
      <guid>https://dev.to/aws-builders/switch-between-aws-accounts-in-your-cli-like-never-before-l9b</guid>
      <description>&lt;p&gt;Struggling with hopping between thousands of AWS Accounts and assuming millions of roles on your CLI? Is storing and managing credentials a headache for you? Don’t worry… I have got your back! Just follow me till the end :)&lt;/p&gt;

&lt;p&gt;Managing programmatic access to AWS has always been troublesome. I have been in this situation quite a lot, and that forced me to look out for ways to simplify my life so that I can focus more on getting things done quicker, without the hassle of remembering Account IDs, AWS Role names, and a whole lot of other things. Phew!&lt;/p&gt;

&lt;p&gt;Without any fancy intro, let’s get right into it.&lt;/p&gt;




&lt;p&gt;Let me walk you through some approaches to authenticating and gaining access to AWS resources programmatically or from the AWS CLI.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The following approaches expects that you already have access to SSO authentication within IAM Identity Center, for yourself to be able to use it. You should ideally have met &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html#cli-configure-sso-prereqs" rel="noopener noreferrer"&gt;these prerequisites&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short, you should be able to see the following screen:&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%2Fgxfg9545tnb6525e4zbe.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%2Fgxfg9545tnb6525e4zbe.png" alt="AWS SSO Portal" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access this page using the SSO start URL, which usually appears like &lt;code&gt;https://d-1a2bc34de5.awsapps.com/start/&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Special Tip:&lt;/strong&gt; You can customize the SSO Start URL as well to something of your choice very easily, simply by following &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/howtochangeURL.html" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;br&gt;
This changes &lt;code&gt;https://d-1a2bc34de5.awsapps.com/start/&lt;/code&gt; → &lt;code&gt;https://mysso-myway.awsapps.com/start/&lt;/code&gt;. This is extremely helpful, as it is often hard to remember these similar looking URLs, especially when you have multiple such SSO URLs. :)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Approach #1: Exporting Environment Variables
&lt;/h2&gt;

&lt;p&gt;The very first and foremost approach, which is quite a common way is to export the temporary credentials as environment variables. This method is especially useful for temporary access, and scripting.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; Obtain Temporary Credentials (Access Keys) for the account and role, from the AWS Access Portal:&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%2F39xj17q1n6lj33wcjods.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%2F39xj17q1n6lj33wcjods.png" alt="Temporary Credential Page" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; Export the copied credentials as environment variables, in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export AWS_ACCESS_KEY_ID=&amp;lt;YourAccessKeyId&amp;gt;
export AWS_SECRET_ACCESS_KEY=&amp;lt;YourSecretAccessKey&amp;gt;
export AWS_SESSION_TOKEN=&amp;lt;YourSessionToken&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can confirm the allowed access by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws sts get-caller-identity
{
    "UserId": "ABCD1234EFGH5678IJKL9:ibatulanand+test+@gmail.com",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/AWSReservedSSO_personal_a12b345cde6fg789/ibatulanand+test+@gmail.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My take on this approach:&lt;/strong&gt; &lt;br&gt;
It’s easy-peasy to gain access and switching accounts only requires copying and exporting environment variables of other accounts. This is what most of the people I have heard of use because of its simplicity, and effectiveness mainly for temporary access or development purposes.&lt;br&gt;
But, as I mentioned, it is effective for temporary use only. Moreover, the credentials are exposed in the environment as well, which isn’t the best.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Approach #2: Configuring AWS-provided Wizard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Using “aws configure sso” wizard
&lt;/h3&gt;

&lt;p&gt;This solution is particularly native to AWS, as it provides profile management through the &lt;code&gt;aws configure sso&lt;/code&gt; wizard and this method is quite user-friendly for setting up multiple profiles.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; Run the configuration wizard and provide the following information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws configure sso
SSO session name (Recommended): mysso
SSO start URL [None]: https://mysso-myway.awsapps.com/start/
SSO region [None]: ap-northeast-1
SSO registration scopes [None]: sso:account:access
Attempting to automatically open the SSO authorization page in your default browser.
If the browser does not open or you wish to use a different device to authorize this request, open the following URL:

https://device.sso.ap-northeast-1.amazonaws.com/

Then enter the code:
FTXD-TLBW

...   ...
&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%2Fouuray5lo3ih9903oa69.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%2Fouuray5lo3ih9903oa69.png" alt="Authorization Code" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76gepyy658svrv81yaif.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%2F76gepyy658svrv81yaif.png" alt="Allow Access" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhz4tivpxrjuw10p79as.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%2Fkhz4tivpxrjuw10p79as.png" alt="Request Approved" width="720" height="387"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

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

There are 5 AWS accounts available to you.
Using the account ID 111111111111
The only role available to you is: personal
Using the role name "personal"
CLI default client Region [ap-northeast-1]:
CLI default output format [None]:
CLI profile name [personal]:

To use this profile, specify the profile name using --profile, as shown:
aws s3 ls --profile personal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the access by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sts get-caller-identity --profile personal
{
    "UserId": "ABCD1234EFGH5678IJKL9:atul-test@gmail.com",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/AWSReservedSSO_personal_a12b345cde6fg789/atul-test@gmail.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also confirm this by checking the &lt;code&gt;~/.aws/config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat ~/.aws/config     

[default]
region = ap-northeast-1

[profile personal]
sso_session = mysso
sso_account_id = 111111111111
sso_role_name = personal
region = ap-northeast-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My take on this approach:&lt;/strong&gt;&lt;br&gt;
It definitely is a better and sort of long-term solution, as compared to the first approach. And, it simplifies the setup process and integrates seamlessly with AWS SSO.&lt;br&gt;
But, the wizard itself has limited capabilities and may require a lot of effort in case you have multiple accounts and roles. Also, you would need to create as many different profiles for each combination.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Using “aws configure sso-session” wizard
&lt;/h3&gt;

&lt;p&gt;This is the new addition to the approaches by AWS, and as per AWS, it is not compatible with the legacy IAM Identity Center.&lt;/p&gt;

&lt;p&gt;Following a similar procedure as the &lt;code&gt;aws configure sso&lt;/code&gt;, you will be able to create an &lt;code&gt;sso-session&lt;/code&gt; in the &lt;code&gt;~/.aws/config&lt;/code&gt; file, which will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat ~/.aws/config     

[default]
region = ap-northeast-1

[profile personal]
sso_session = mysso
sso_account_id = 111111111111
sso_role_name = personal
region = ap-northeast-1

[sso-session mysso]
sso_start_url = https://mysso-myway.awsapps.com/start/
sso_region = ap-northeast-1
sso_registration_scopes = sso:account:access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real benefit of this method is that it allows &lt;code&gt;sso-session&lt;/code&gt; configurations to be reused across multiple profiles, like dev, pre-prod, prod, or any profile categorization you may have.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My take on this approach:&lt;/strong&gt;&lt;br&gt;
This approach sounds most promising so far, as it offers advanced configuration options, and fine-grained control over sessions. Also, these wizard bases approaches allow to retrieve and cache a set of credentials by running these commands:&lt;br&gt;
“$ aws sso login — profile personal” OR “$ aws sso login — sso-session mysso”&lt;br&gt;
But, it still is complex to setup and requires additional management in the future.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Approach #3: Using the “aws-sso-cli” utility tool
&lt;/h2&gt;

&lt;p&gt;Now comes the one I was waiting to tell you all about!&lt;br&gt;
This approach enhances the experience with a simple, yet powerful, utility tool that provides so much convenience and flexibility. This tool is an absolute game-changer, making the whole process of switching accounts and assuming roles incredibly smooth.&lt;/p&gt;

&lt;p&gt;I can’t emphasize enough how much &lt;code&gt;aws-sso-cli&lt;/code&gt; has improved my workflow, especially because it offers a streamlined and intuitive interface.&lt;/p&gt;

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

&lt;p&gt;[1] Install the &lt;code&gt;aws-sso-cli&lt;/code&gt; utility tool following the &lt;a href="https://synfinatic.github.io/aws-sso-cli/latest/quickstart/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;, or if you’re on Mac, you can simply install it using Homebrew using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install aws-sso-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[2] Run the following command to do the basic configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws-sso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow us to set permission up like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3ipxeymesjcl85flp1h.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%2Fv3ipxeymesjcl85flp1h.png" alt="Authorization Requested" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy820dfezqtyzd0djjy0b.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%2Fy820dfezqtyzd0djjy0b.png" alt="Allow" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ljoulkpyarznhn93ogk.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%2F2ljoulkpyarznhn93ogk.png" alt="Request Approved" width="720" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, after the configuration is done, it shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws-sso

 Verify this code in your browser: XTRD-XZBM
List of AWS roles for SSO Instance: Default [Expires in: 6h  2m]

AccountIdPad | AccountAlias        | RoleName       | Profile                     | Expires
=======================================================================================================
111111111111 | Atul Anand          | personal       | 111111111111:personal       | Expired
222222222222 | xxx-xxxxx-xxxxx     | admin          | 222222222222:admin          | Expired
333333333333 | yyy-yyyyy-yyyyy     | admin          | 333333333333:admin          | Expired
444444444444 | zzz-zzzzz-zzzzz     | developer      | 444444444444:developer      | Expired
555555555555 | test                | developer      | 555555555555:developer      | Expired
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even enable Auto-completion using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws-sso completions -I
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more about auto-completion &lt;a href="https://github.com/synfinatic/aws-sso-cli/blob/main/docs/commands.md#setup-completions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To switch accounts, simply run the command (with tabs to auto-complete):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws-sso-profile 111111111111:personal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, finally, confirm the access by running the same command as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sts get-caller-identity
{
    "UserId": "ABCD1234EFGH5678IJKL9:atul-test@gmail.com",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/AWSReservedSSO_personal_a12b345cde6fg789/atul-test@gmail.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a lot of other features available with this tool. So, if you are interested in knowing and trying out more, refer to these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://synfinatic.github.io/aws-sso-cli/latest/" rel="noopener noreferrer"&gt;https://synfinatic.github.io/aws-sso-cli/latest/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/synfinatic/aws-sso-cli" rel="noopener noreferrer"&gt;https://github.com/synfinatic/aws-sso-cli&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My take on this approach:&lt;/strong&gt;&lt;br&gt;
This is the most intuitive, easy-to-setup, and full of features approach that really elevates the experience of working with multiple AWS accounts and roles.&lt;br&gt;
The only thing is that it’s a third party open-source tool, which might be a concern for a few people, but not the majority.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;If you are also willing to try, have already tried &lt;code&gt;aws-sso-cli&lt;/code&gt;, or know of any other alternatives, please let me know and share with other fellow AWS buddies.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://levelup.gitconnected.com/juggle-between-aws-accounts-in-your-cli-like-never-before-15076066fc80" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>sso</category>
      <category>programming</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
