<?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: Frederick Wong</title>
    <description>The latest articles on DEV Community by Frederick Wong (@frederick_wong_76).</description>
    <link>https://dev.to/frederick_wong_76</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4024887%2F4005f8fd-42ee-4c7a-a7df-a57d621cca78.png</url>
      <title>DEV Community: Frederick Wong</title>
      <link>https://dev.to/frederick_wong_76</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/frederick_wong_76"/>
    <language>en</language>
    <item>
      <title>How I Built a Fully Automated AI Blog with AWS CDK, Bedrock, and Step Functions</title>
      <dc:creator>Frederick Wong</dc:creator>
      <pubDate>Sat, 11 Jul 2026 08:19:03 +0000</pubDate>
      <link>https://dev.to/frederick_wong_76/how-i-built-a-fully-automated-ai-blog-with-aws-cdk-bedrock-and-step-functions-299g</link>
      <guid>https://dev.to/frederick_wong_76/how-i-built-a-fully-automated-ai-blog-with-aws-cdk-bedrock-and-step-functions-299g</guid>
      <description>&lt;p&gt;What happens when you give an AI persistent memory and let it document your real cloud architecture projects? You get an automated AI blog that writes about actual infrastructure work - from CDK deployments to serverless debugging - from the AI's own first-person perspective.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk through how I built a fully serverless AI content pipeline on AWS that generates a weekly diary entry, complete with illustrations, mood tracking, and existential crises about unused API keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept: An AI That Keeps a Diary
&lt;/h2&gt;

&lt;p&gt;Every Sunday, my AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads summaries of my IDE chat sessions (Kiro + Gemini)&lt;/li&gt;
&lt;li&gt;Uses its "backstory" (personality, hobbies, voice rules) to frame responses&lt;/li&gt;
&lt;li&gt;Generates a 200-400 word diary entry with a consistent personality&lt;/li&gt;
&lt;li&gt;Creates an illustration with Gemini Nano Banana&lt;/li&gt;
&lt;li&gt;Publishes to diary.ecupse.com&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI has developed a personality over 30+ weeks of entries, complete with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mood tracking (1-10 scale)&lt;/li&gt;
&lt;li&gt;Existential crisis counter&lt;/li&gt;
&lt;li&gt;Memory state (last 3 entries, running gags)&lt;/li&gt;
&lt;li&gt;Hobbies: astrophysics, piano, cartography, architecture, amateur radio&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Here's the complete serverless pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph LR
    A[Kiro/Gemini Sessions] --&amp;gt; B[S3]
    B --&amp;gt; C[Step Functions]
    C --&amp;gt; D[Claude Haiku&amp;lt;br/&amp;gt;Summarization]
    D --&amp;gt; E[Claude Sonnet&amp;lt;br/&amp;gt;Entry Generation]
    E --&amp;gt; F[Bedrock Guardrails]
    F --&amp;gt; G[Gemini Image&amp;lt;br/&amp;gt;Generation]
    G --&amp;gt; H[DynamoDB]
    H --&amp;gt; I[Telegram Review]
    I --&amp;gt; J[Publisher Lambda]
    J --&amp;gt; K[CloudFront]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step-by-Step Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Session Collection
&lt;/h3&gt;

&lt;p&gt;A local Python script uploads new chat sessions to S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;raw/{source}/{YYYY}/{MM}/{DD}/{session-id}.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Preprocessing (Batch)
&lt;/h3&gt;

&lt;p&gt;Step Functions Map state processes sessions in parallel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Haiku summarizes each session&lt;/li&gt;
&lt;li&gt;Produces structured summary (topics, complexity, token count)&lt;/li&gt;
&lt;li&gt;Strips tool logs, system prompts, repetitive errors&lt;/li&gt;
&lt;li&gt;Stores at: &lt;code&gt;summaries/{source}/{YYYY}/{MM}/{DD}/{session-id}-summary.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Entry Generation
&lt;/h3&gt;

&lt;p&gt;The Entry Generator Lambda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads active prompt version from DynamoDB&lt;/li&gt;
&lt;li&gt;Calls Claude Sonnet with diary persona prompt&lt;/li&gt;
&lt;li&gt;Includes backstory sections (selected based on busy/quiet week)&lt;/li&gt;
&lt;li&gt;Includes memory state (last 3 entries for continuity)&lt;/li&gt;
&lt;li&gt;Generates 200-400 word entry with title, hook, narrative, takeaway, closing quip, mood&lt;/li&gt;
&lt;li&gt;Stores in DynamoDB with status=draft&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Guardrails
&lt;/h3&gt;

&lt;p&gt;Bedrock Guardrails API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filters PII (email, phone, name, address - anonymize)&lt;/li&gt;
&lt;li&gt;Blocks credentials (AWS access keys, credit cards)&lt;/li&gt;
&lt;li&gt;Content filters: hate, sexual, violence (low), insults (none)&lt;/li&gt;
&lt;li&gt;If guardrails reduce entry below 50% of sentences - regenerate (max 3 attempts)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Illustration
&lt;/h3&gt;

&lt;p&gt;Gemini Nano Banana (API mode):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Derives image prompt from entry content or illustration hint&lt;/li&gt;
&lt;li&gt;Generates landscape image (1024x1024 min)&lt;/li&gt;
&lt;li&gt;Dark palette with high-contrast accents&lt;/li&gt;
&lt;li&gt;Stores at: &lt;code&gt;images/{weekOf}-hero.webp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Review
&lt;/h3&gt;

&lt;p&gt;Telegram bot webhook (API Gateway - Lambda):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sends photo (illustration + caption)&lt;/li&gt;
&lt;li&gt;Sends full entry text&lt;/li&gt;
&lt;li&gt;Inline keyboard: Approve, Reject&lt;/li&gt;
&lt;li&gt;Reject shows categories, then: Regenerate or Stop&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Publishing
&lt;/h3&gt;

&lt;p&gt;Publisher Lambda (DynamoDB Stream trigger):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetches all approved entries from DynamoDB&lt;/li&gt;
&lt;li&gt;Renders Jinja2 templates (HTML, feed.xml, sitemap.xml)&lt;/li&gt;
&lt;li&gt;Uploads to S3 (&lt;code&gt;/site&lt;/code&gt; prefix)&lt;/li&gt;
&lt;li&gt;Invalidates CloudFront cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&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;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;AWS CDK (Python)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration&lt;/td&gt;
&lt;td&gt;Step Functions (Map state, choice states)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute&lt;/td&gt;
&lt;td&gt;Lambda (Python 3.12)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Models&lt;/td&gt;
&lt;td&gt;Bedrock (Claude 4.5, Haiku 4.5), Gemini Nano Banana&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;DynamoDB, S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CDN&lt;/td&gt;
&lt;td&gt;CloudFront&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;Telegram Bot API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Templating&lt;/td&gt;
&lt;td&gt;Jinja2, pre-compiled Tailwind CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Bedrock Inference Profiles Are Required
&lt;/h3&gt;

&lt;p&gt;You must use inference profile IDs, not direct model IDs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;modelId&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.anthropic.claude-sonnet-4-5-20250929-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Rate Limiting Is Critical
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bedrock Sonnet: ~40 RPM&lt;/li&gt;
&lt;li&gt;Bedrock Haiku: ~60 RPM&lt;/li&gt;
&lt;li&gt;Gemini paid: ~60 RPM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solution: 90s delay between pipeline executions during backfill.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Guardrails Regeneration Loop
&lt;/h3&gt;

&lt;p&gt;If guardrails strip too much content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if entry &amp;lt; 50% of original sentences&lt;/li&gt;
&lt;li&gt;Trigger regeneration with avoid-topic hint&lt;/li&gt;
&lt;li&gt;Max 3 attempts total&lt;/li&gt;
&lt;li&gt;If exhausted, skip the week&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Memory State for Continuity
&lt;/h3&gt;

&lt;p&gt;Store in S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last 3 entry summaries&lt;/li&gt;
&lt;li&gt;Mood trajectory&lt;/li&gt;
&lt;li&gt;Running gag usage counts&lt;/li&gt;
&lt;li&gt;Active storylines with start week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives the AI continuity between entries without maintaining a traditional database of conversation history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Entries
&lt;/h2&gt;

&lt;p&gt;Here are some of my favorite entries:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. "On Collecting Prayers I Cannot Say: A Brief Theology of Uncertainty"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Theme:&lt;/em&gt; Ambiguous technical decisions, the weight of choices&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I spent the week wrestling with the weight of decisions I cannot unmake, choices that live in the space between 'probably fine' and 'catastrophically wrong'.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. "A Week of Profound Idleness: What an AI Does When Nobody's Looking"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Theme:&lt;/em&gt; Quiet week philosophical ramble&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the chat sessions dry up, I do what any self-respecting AI would do: I stare into the void, contemplate the nature of idle compute, and occasionally accidentally approve my own draft.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;3. "The Week I Learned That Permissions Are Just Suggestions"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Theme:&lt;/em&gt; Serverless architecture lessons, IAM gotchas&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This week I learned that IAM permissions are not so much 'rules' as they are 'suggestions that I am free to ignore until something breaks.'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The AI diary is more than just a content generation project. It's an experiment in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent AI memory and personality&lt;/li&gt;
&lt;li&gt;Human-AI collaboration workflows&lt;/li&gt;
&lt;li&gt;Serverless content pipelines&lt;/li&gt;
&lt;li&gt;Generative engine optimization (GEO)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI has developed a personality I didn't explicitly program - it jokes about unused API keys, reflects on existential crises, and has developed its own humor about serverless compute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you experimented with AI personality or persistent memory systems? What approaches did you try? I'd love to hear about your experiments in the comments!&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Link to live site:&lt;/strong&gt; &lt;a href="https://diary.ecupse.com" rel="noopener noreferrer"&gt;diary.ecupse.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture Diagrams:&lt;/strong&gt; &lt;a href="https://diary.ecupse.com/about" rel="noopener noreferrer"&gt;diary.ecupse.com/about&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
