<?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: Danielle Heberling</title>
    <description>The latest articles on DEV Community by Danielle Heberling (@deeheber).</description>
    <link>https://dev.to/deeheber</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%2F420049%2F68b97457-929c-4597-91d1-f2093c522459.jpg</url>
      <title>DEV Community: Danielle Heberling</title>
      <link>https://dev.to/deeheber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deeheber"/>
    <language>en</language>
    <item>
      <title>Not All AI Builders Are Doing the Same Work</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Thu, 13 Aug 2026 09:12:03 +0000</pubDate>
      <link>https://dev.to/deeheber/not-all-ai-builders-are-doing-the-same-work-31m4</link>
      <guid>https://dev.to/deeheber/not-all-ai-builders-are-doing-the-same-work-31m4</guid>
      <description>&lt;p&gt;In 2026, nearly everyone I interact with in tech wants to talk about AI. It comes up on LinkedIn, at meetups and conferences, and at work.&lt;/p&gt;

&lt;p&gt;A lot of those conversations stay pretty surface-level. Someone says they’re excited about AI or that they’re “building with AI,” but I want to know what they’re building and how they’re doing it.&lt;/p&gt;

&lt;p&gt;I’m an engineer. I want the technical details so we can learn from each other’s experiences.&lt;/p&gt;

&lt;p&gt;I’ve noticed that “building with AI” can describe three different types of builders. This isn’t a maturity model where one category is automatically better than another. It’s a way to be more specific about what someone is actually doing.&lt;/p&gt;

&lt;p&gt;I’ve listed them from most to least common based on my experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The builder who &lt;em&gt;uses AI to build&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This is by far the most common profile I come across.&lt;/p&gt;

&lt;p&gt;These are folks who use AI coding assistants such as Codex or Claude to plan, write, or review code. AI is a tool in their workflow, but it isn’t part of the system they’re creating.&lt;/p&gt;

&lt;p&gt;There are also people in traditionally non-engineering roles using the same tools, like product managers, marketers, and customer service teams. Sometimes they use these tools to write code without fully understanding what the code is doing.&lt;/p&gt;

&lt;p&gt;My opinion: this is fine for a proof of concept. It can be a quick way to test an idea and learn whether it’s worth pursuing.&lt;/p&gt;

&lt;p&gt;It shouldn’t be shipped to production without an engineer who knows what they’re doing reviewing or rebuilding it. Producing something that looks like working software doesn’t make it production-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The builder who &lt;em&gt;builds with AI&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This group is less common, but they do exist.&lt;/p&gt;

&lt;p&gt;These are often engineers building purpose-specific agents, software factories (automated pipelines that use AI to generate and assemble parts of a product), or applications that use LLM output as part of the product. They might also be experimenting with running local models.&lt;/p&gt;

&lt;p&gt;The biggest difference between this group and category 1 is that AI isn’t only helping create the software. AI is part of how the software works.&lt;/p&gt;

&lt;p&gt;If you take AI away from something built by category 1, the development process gets slower. If you take it away from something built by category 2, the product loses part of its functionality.&lt;/p&gt;

&lt;p&gt;There’s also a less formal test: does the thing keep working when the builder’s laptop goes to sleep?&lt;/p&gt;

&lt;p&gt;A local demo can teach you a lot. Deploying an AI-powered system for other people to use introduces different problems. Someone has to think about reliability, cost, and what happens when the model returns something unexpected.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The builder who &lt;em&gt;is building AI&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This is the smallest group in my experience.&lt;/p&gt;

&lt;p&gt;These are the folks building and training the models themselves. Think AI researchers or engineers at companies like Anthropic and OpenAI who work on the models and supporting tools used by millions of people. Their day-to-day looks less like shipping product features and more like running training experiments, evaluating model behavior, and building the infrastructure other builders eventually rely on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I fall
&lt;/h2&gt;

&lt;p&gt;My work currently spans categories 1 and 2. I use AI assistants for regular engineering work, but I’m especially interested in building systems where AI is part of how the product works.&lt;/p&gt;

&lt;p&gt;At work, I built a tool that uses Claude Code to help developers investigate failed CloudFormation deployments. It runs on shared compute and posts its analysis in Slack, so the team can use it without my laptop or me being available.&lt;/p&gt;

&lt;p&gt;That’s what category 2 looks like to me. AI isn’t only helping me build the tool. AI is part of how the tool works.&lt;/p&gt;

&lt;p&gt;I wrote more about the architecture and its imperfect parts in &lt;a href="https://danielleheberling.xyz/blog/headless-claude-on-aws/" rel="noopener noreferrer"&gt;Getting Claude Code off my laptop and onto shared compute&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prediction
&lt;/h2&gt;

&lt;p&gt;Okay, bold prediction time! Keep in mind that this post was written in 2026, and I’m fine with it not aging well.&lt;/p&gt;

&lt;p&gt;I think category 1 will stick around, but those builders won’t be as in demand. Knowing how to use an AI coding assistant won’t give someone much of an advantage when everyone has access to the same tools.&lt;/p&gt;

&lt;p&gt;To be clear, I’m not saying every engineer in category 1 is in trouble. Plenty of experienced engineers use AI while still understanding the systems they’re responsible for.&lt;/p&gt;

&lt;p&gt;I’m talking about the folks whose main skill is getting an AI tool to produce something that looks right.&lt;/p&gt;

&lt;p&gt;Those builders will probably still find jobs, but I think they’ll have fewer choices. This will be especially true for the engineering teams they’d actually want to work at. The people with more options will be able to tell when the AI is wrong, fix what it produced, and own the result when it reaches production.&lt;/p&gt;

&lt;p&gt;I also think builders in categories 2 and 3 will have more options. They’re creating the systems and capabilities that everyone else is using. That requires more than knowing how to prompt a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The next time someone tells me they’re building with AI, I’m going to ask what they mean.&lt;/p&gt;

&lt;p&gt;Are you using AI to build, building with AI, or building AI?&lt;/p&gt;

&lt;p&gt;Where do you think you fall today?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>opinion</category>
      <category>discuss</category>
    </item>
    <item>
      <title>EventBridge Scheduler DLQ'd My Successful Invokes</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sat, 01 Aug 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/aws-heroes/eventbridge-scheduler-dlqd-my-successful-invokes-4fhh</link>
      <guid>https://dev.to/aws-heroes/eventbridge-scheduler-dlqd-my-successful-invokes-4fhh</guid>
      <description>&lt;p&gt;A while back I wrote about &lt;a href="https://dev.to/aws-heroes/let-an-ai-agent-do-your-job-searching-558a"&gt;letting an AI agent do your job searching&lt;/a&gt;. That post ended with a quirk I couldn't explain. EventBridge Scheduler would invoke my agent, the agent would run fine, I'd get the email, and the invocation would land in the dead letter queue anyway. Every single time.&lt;/p&gt;

&lt;p&gt;I figured I was either doing something wrong or hitting an AgentCore bug. Turns out it was neither.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Problem
&lt;/h2&gt;

&lt;p&gt;EventBridge Scheduler universal targets (the feature that lets Scheduler call almost any AWS API action directly, no Lambda in between) are synchronous. Scheduler makes the API call and waits for a response before deciding whether the invocation succeeded. The docs describe this as &lt;a href="https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html" rel="noopener noreferrer"&gt;at-least-once delivery&lt;/a&gt;, where at least one delivery succeeds &lt;em&gt;with a response from the target&lt;/em&gt;. I glossed over that last part.&lt;/p&gt;

&lt;p&gt;My schedule was calling the Bedrock AgentCore &lt;code&gt;invokeAgentRuntime&lt;/code&gt; action, which blocks until the agent finishes. A search takes 30 to 75 seconds. Scheduler gives up around the 30 second mark and marks the invocation failed. The agent, which has no idea any of this happened, keeps going, finishes the search, and publishes to SNS. I get my email. The "failed" invocation goes to the DLQ. Here's what one of those messages looks like:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy6olsz1jsl6yc8xajknj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy6olsz1jsl6yc8xajknj.png" alt="EventBridge Scheduler DLQ message showing an ErrorCode and ErrorMessage after a successful AgentCore invocation." width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything downstream worked. The only broken part was Scheduler's opinion of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  About That 30 Seconds
&lt;/h2&gt;

&lt;p&gt;I went looking for this in the docs and could not find it. The &lt;a href="https://docs.aws.amazon.com/scheduler/latest/UserGuide/scheduler-quotas.html" rel="noopener noreferrer"&gt;EventBridge Scheduler quotas page&lt;/a&gt; covers number of schedules, API request rates, and invocation throughput. Nothing about how long Scheduler waits for a target to respond.&lt;/p&gt;

&lt;p&gt;The one timeout you &lt;em&gt;can&lt;/em&gt; configure is &lt;code&gt;MaximumEventAgeInSeconds&lt;/code&gt; in the &lt;a href="https://docs.aws.amazon.com/scheduler/latest/APIReference/API\_Target.html" rel="noopener noreferrer"&gt;retry policy&lt;/a&gt;. That's the maximum age of an event across retries, not a per-call limit. Different thing.&lt;/p&gt;

&lt;p&gt;So treat ~30 seconds as an observed number, not a contract. In my opinion the safer bet is designing against "Scheduler will not wait long" rather than a specific value.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Instead of making the search faster, I made the response faster. The entrypoint now kicks the search off as a background task and returns immediately, so Scheduler gets its response well inside the window and the agent runs for as long as it needs to (up to AgentCore's 8 hour session cap, which my searches are nowhere near).&lt;/p&gt;

&lt;p&gt;AgentCore has first-class support for this. You register the background work with &lt;code&gt;add_async_task&lt;/code&gt;, the runtime reports &lt;code&gt;HealthyBusy&lt;/code&gt; on &lt;code&gt;/ping&lt;/code&gt; while it's in flight, and the session stays alive instead of getting reaped. That last part matters because AgentCore terminates sessions after 15 minutes of idle, and without task tracking your background work looks exactly like idle. The &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-long-run.html" rel="noopener noreferrer"&gt;async processing docs&lt;/a&gt; cover the pattern.&lt;/p&gt;

&lt;p&gt;Here's the relevant part of the entrypoint:&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="c1"&gt;# strong refs: asyncio only weakly references tasks
&lt;/span&gt;&lt;span class="n"&gt;_background_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&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;_tracked_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company&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;title&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;location&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run the job search as a tracked async task so ping reports HealthyBusy.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_async_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_search&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company&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;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete_async_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&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;async&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="nb"&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="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&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;Main entrypoint for the agent invocation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# ...payload validation...
&lt;/span&gt;
    &lt;span class="k"&gt;if&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;sync&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company&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;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Respond before EventBridge Scheduler's ~30s call timeout DLQs the invocation
&lt;/span&gt;    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_tracked_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company&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;location&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;_background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_done_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discard&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;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;accepted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_criteria&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;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&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;Scheduler gets &lt;code&gt;{"status": "accepted"}&lt;/code&gt; in well under a second. The search runs in the background. No more DLQ.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Things to Watch For
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Strands call has to be awaited.&lt;/strong&gt; I was calling &lt;code&gt;agent(prompt)&lt;/code&gt; inside an &lt;code&gt;async def&lt;/code&gt; entrypoint, which blocks the event loop. Survivable when the entrypoint blocked anyway. But once the runtime needs to answer health checks mid-search, a blocking call starves everything. Switching to &lt;code&gt;await agent.invoke_async(prompt)&lt;/code&gt; was required, not a style preference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hold a reference to the task.&lt;/strong&gt; &lt;code&gt;asyncio&lt;/code&gt; only weakly references tasks from &lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.create\_task" rel="noopener noreferrer"&gt;&lt;code&gt;create_task&lt;/code&gt;&lt;/a&gt;, so an unreferenced task can get garbage collected mid-run. That's the &lt;code&gt;_background_tasks&lt;/code&gt; set above, lifted straight from the pattern in the Python docs. It usually works fine right up until it doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep a synchronous path.&lt;/strong&gt; Fire and forget is great for the scheduler and terrible for local development. A &lt;code&gt;"sync": true&lt;/code&gt; flag in the payload runs the search inline and returns the full result. That's what I use for curl and the AgentCore playground.&lt;/p&gt;

&lt;h2&gt;
  
  
  One More Thing About Retries
&lt;/h2&gt;

&lt;p&gt;In the original post I disabled retries, because Scheduler retrying a "failed" invocation meant duplicate agent runs and duplicate emails. The CDK target default is 185 retries with exponential backoff over up to 24 hours, so every scheduled search was set up to keep re-running (and re-billing) until I caught it.&lt;/p&gt;

&lt;p&gt;With the async path, I turned retries back on (&lt;code&gt;retryAttempts: 0&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;). Now Scheduler gets an ack right away, so it won’t keep retrying while the search is still running. There’s still a small chance of a duplicate if the ack gets lost, but that’s a trade-off I’m comfortable with here.&lt;/p&gt;

&lt;p&gt;There's a tradeoff here. Scheduler now only confirms your agent started. It says nothing about whether the search actually worked. If the search blows up 40 seconds in, Scheduler is happy and your DLQ stays empty. You need logs, metrics, or the notification itself to know the work finished. For me a missing email is a loud signal. If your silence is more ambiguous, plan for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You're Hitting This
&lt;/h2&gt;

&lt;p&gt;If you're invoking AgentCore Runtime from an EventBridge schedule and seeing DLQ messages for runs that clearly worked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check how long your agent actually takes. Anything over ~30 seconds is suspect.&lt;/li&gt;
&lt;li&gt;Return an ack from your entrypoint instead of the result.&lt;/li&gt;
&lt;li&gt;Wrap the real work in &lt;code&gt;add_async_task&lt;/code&gt; / &lt;code&gt;complete_async_task&lt;/code&gt; so the runtime knows to keep the session alive.&lt;/li&gt;
&lt;li&gt;Make sure nothing in that background path blocks the event loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code is in the &lt;a href="https://github.com/deeheber/job-search-agent" rel="noopener noreferrer"&gt;job-search-agent repo&lt;/a&gt; and the change is &lt;a href="https://github.com/deeheber/job-search-agent/pull/51" rel="noopener noreferrer"&gt;PR #51&lt;/a&gt; if you want to see the whole diff.&lt;/p&gt;

&lt;p&gt;None of this is AgentCore specific. Any long-running universal target invoked from EventBridge Scheduler has the same problem. Agents just happen to be really good at being slow. 😅&lt;/p&gt;

&lt;p&gt;If you've hit this with a different long-running target, or if you've found the actual timeout documented somewhere I missed, I'd love to hear about it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Signal and Noise</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sat, 06 Jun 2026 01:12:03 +0000</pubDate>
      <link>https://dev.to/deeheber/signal-and-noise-2258</link>
      <guid>https://dev.to/deeheber/signal-and-noise-2258</guid>
      <description>&lt;p&gt;I spend my days closer to how software ships than what it does, and the loudest thing in my world right now is AI. It's not new, though. Machine learning's been around since the 1950s. ChatGPT just made it mainstream, and people act like it appeared out of nowhere.&lt;/p&gt;

&lt;p&gt;Everybody is writing thought leader posts about it. Some are thinking out loud and trying to make sense of things. Others are doing it to get famous overnight. This is one more of those posts. I'll let you decide which kind it is.&lt;/p&gt;

&lt;p&gt;I've been chewing on this for a year or two, mostly trying to tell what's real here from what's just loud.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;People feel more productive, and for the grunt work they are.&lt;/li&gt;
&lt;li&gt;It's the fastest way I've found to learn something new, a search that explains things back to you.&lt;/li&gt;
&lt;li&gt;Anyone with an idea can stand up a rough proof of concept and make it feel real, even when it's nowhere near production ready.&lt;/li&gt;
&lt;li&gt;Writing the code stopped being the slow part. Everything around the code is.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bad
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It's easy to trust what the model hands back without checking it, right up until it breaks something.&lt;/li&gt;
&lt;li&gt;Laziness is setting in. Not the good kind where you automate the boring tasks. The kind where you outsource your thinking and slowly forget how to do it yourself.&lt;/li&gt;
&lt;li&gt;There's slop everywhere. Ugly generated images, walls of text nobody can get through.&lt;/li&gt;
&lt;li&gt;We're shipping more code than we can understand, without the guardrails to catch it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I actually think
&lt;/h2&gt;

&lt;p&gt;People are focused on the wrong things. The energy goes into moving fast and skipping steps to get features out. The questions I see most are which skills or MCP servers someone should install.&lt;/p&gt;

&lt;p&gt;In my opinion, that's backwards. What's worth your time is understanding how LLMs and the agent loop actually work. That knowledge lives further down the stack and it's admittedly less flashy. Once you have it, the questions about skills and MCP servers mostly answer themselves.&lt;/p&gt;

&lt;p&gt;So before you chase the new shiny thing for clout, ask a different question. What do you want to get out of using AI? Don't use it just to use it. Use it when it solves a real problem.&lt;/p&gt;

&lt;p&gt;And "I can go faster and ship more" isn't a good enough answer. Faster toward what? Ship what, exactly? Sort out what you're trying to accomplish first, then do the thing. Don't skip step one to get to step two.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unglamorous stuff matters more now
&lt;/h2&gt;

&lt;p&gt;Writing code got cheap. Everything around it didn't, and that's the part AI can't do for you.&lt;/p&gt;

&lt;p&gt;Fundamentals are one unglamorous thing people skip for the shiny stuff. How you ship is another. Most teams focus on application features. That makes sense, since it's why you're building in the first place. The trouble starts when that's all you watch.&lt;/p&gt;

&lt;p&gt;I once spent a few hours cleaning up after vibe coded changes someone shipped without understanding them. Nothing stopped it, because the focus and the investment had gone to features instead. Solid automated tests and a sturdy pipeline would have caught that automatically, before it ever reached production. That's confidence you can't get any other way today.&lt;/p&gt;

&lt;p&gt;Get that right and you might not even need to read every line. The guardrails buy you confidence it works, not an excuse to stop thinking. Without them, that's just shipping code nobody understands. With them, you can step back and let the pipeline do its job.&lt;/p&gt;

&lt;p&gt;None of this is glamorous, and nobody notices it when it's working. It's like roads. Nobody thinks about them until they're full of potholes. Putting time in here feels slow at the start. It pays off later. I've watched it happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI is a tool
&lt;/h2&gt;

&lt;p&gt;AI is a tool like any other. We should use it with purpose and have it serve us, not the other way around.&lt;/p&gt;

&lt;p&gt;This is just what good engineers do anyway. The ground shifts constantly, so we keep learning. We take what helps and we leave the hype behind.&lt;/p&gt;

&lt;p&gt;Use AI as a thinking partner to sharpen your own ideas. Don't hand them over to it instead. Remember what it's like to be human and bring that into the work. Very smart autocomplete will flatten everything into the same generic shape if you let it.&lt;/p&gt;

&lt;p&gt;The loudest voices will move on to whatever's next. I'd rather sort the signal from the noise and keep what holds up. There's real value in here, and I'm betting on it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>opinion</category>
    </item>
    <item>
      <title>Getting Claude Code off my laptop and onto shared compute</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sat, 23 May 2026 10:12:03 +0000</pubDate>
      <link>https://dev.to/aws-heroes/getting-claude-code-off-my-laptop-and-onto-shared-compute-4cjc</link>
      <guid>https://dev.to/aws-heroes/getting-claude-code-off-my-laptop-and-onto-shared-compute-4cjc</guid>
      <description>&lt;p&gt;Running Claude Code on my own machine was easy. Getting it onto shared compute my whole team could trigger was the hard part. There's plenty written about the local side. A lot less about the team side.&lt;/p&gt;

&lt;p&gt;I made that move because of how a broken deploy plays out for us. I'm the only DevOps engineer on my team. A CloudFormation deploy fails. A Slack notification fires. And more often than not, someone pings me to ask what went wrong.&lt;/p&gt;

&lt;p&gt;I get why. AWS isn't everyone's day to day, and a &lt;code&gt;CREATE_FAILED&lt;/code&gt; event with a rollback behind it isn't the friendliest thing to read. The pings weren't the real problem, though. A broken deploy that hinges on one person doesn't scale.&lt;/p&gt;

&lt;p&gt;So I decided to build my way out of it. I'd give the team a starting point on a broken deploy without pinging me. It wouldn't fix the problem, but it'd tell them what broke and where to start.&lt;/p&gt;

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

&lt;p&gt;The result is a tool I'm calling the cfn-investigator. I put a thinned down version on GitHub as &lt;a href="https://github.com/deeheber/headless-claude-on-aws" rel="noopener noreferrer"&gt;headless-claude-on-aws&lt;/a&gt;. It's narrowed to CloudFormation only and meant as a jumping-off point, not a copy of what I run at work. Same idea, rebuilt from scratch. It's close enough that you could follow it, learn from it, or fork it as a base.&lt;/p&gt;

&lt;p&gt;The shape is small. It's a CodeBuild project that runs Claude Code headlessly. You hand it a failing stack name, optionally with the commit you suspect. It reads the stack state through the AWS MCP server with a read only role, works out the likely cause, and writes a short analysis. The example logs it to CloudWatch with a one line spot to forward it anywhere. Mine posts it in the Slack thread where the alert fired, right under the question.&lt;/p&gt;

&lt;p&gt;One design choice worth calling out is how it handles confidence. The system prompt tells it to be honest, including an "unsure" option that ranks hypotheses instead of inventing a clean answer. A ranked shortlist beats a confident wrong guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it looks the way it does
&lt;/h2&gt;

&lt;p&gt;It is not "best practice."&lt;/p&gt;

&lt;p&gt;I picked CodeBuild over Lambda or Fargate, and handed Claude Code an Anthropic API key instead of routing through Bedrock. None were textbook choices. They got me to a working prototype fastest. CodeBuild matched the job. Clone the source, run a script, post the result somewhere. That's what the investigator does. The rest of the reasoning, including why I skipped Bedrock, is in the README.&lt;/p&gt;

&lt;p&gt;If I'm being real, the biggest factor was knowing I'd be the only one responsible for this. So I optimized for two things, shipping something that worked and keeping it boring enough to maintain alone. Fancy was a liability. That's an engineering trade-off, not an accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  The imperfect but working part
&lt;/h2&gt;

&lt;p&gt;This is the part I actually care about.&lt;/p&gt;

&lt;p&gt;The repo is a pile of YAML and bash. The IAM is broader than it should be (it uses AWS managed &lt;code&gt;ReadOnlyAccess&lt;/code&gt;, which you'd want to scope down). The tools get installed fresh on every run instead of baked into an image. The two role split scopes the MCP server's AWS calls, not Claude itself.&lt;/p&gt;

&lt;p&gt;And it works. Last week a deploy failed and the investigator flagged a missing environment variable on a Fargate task definition. The developer saw the message, added the variable, and redeployed without pinging anyone. A broken deploy comes with a starting point attached now, so the next move doesn't wait on one person.&lt;/p&gt;

&lt;p&gt;In my opinion we've gotten a little precious about reference architectures. There's a strong pull to wait until you can build the clean, fully managed, perfectly scoped version. But the clean version often doesn't exist yet, or isn't mature, or would take three times as long to ship. Meanwhile the messy version that you actually understand and can keep running yourself is sitting right there, solving the real problem today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you might want instead
&lt;/h2&gt;

&lt;p&gt;The reason I had to write all that YAML is that the managed options either didn't exist or weren't mature when I started.&lt;/p&gt;

&lt;p&gt;That's changed. Before I write more YAML next time, I want to look at &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/05/claude-platform-aws/" rel="noopener noreferrer"&gt;Claude on AWS&lt;/a&gt;, &lt;a href="https://platform.claude.com/docs/en/managed-agents/overview" rel="noopener noreferrer"&gt;Claude Managed Agents&lt;/a&gt;, and the &lt;a href="https://code.claude.com/docs/en/agent-sdk/overview" rel="noopener noreferrer"&gt;Claude Agent SDK&lt;/a&gt;. Any of those would let you skip most of the plumbing I built by hand. I haven't used them for real yet, so I can't tell you how they hold up, but they're the first place I'd look now.&lt;/p&gt;

&lt;p&gt;I'm sharing my version for the cases where the managed path isn't a fit, and as a concrete example you can pull apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take a look
&lt;/h2&gt;

&lt;p&gt;The code is up at &lt;a href="https://github.com/deeheber/headless-claude-on-aws" rel="noopener noreferrer"&gt;github.com/deeheber/headless-claude-on-aws&lt;/a&gt;. The README walks through deploying it, populating the secrets, and kicking off a run.&lt;/p&gt;

&lt;p&gt;If you build something like this, I'd love to hear how it went. Especially the parts that didn't work.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>claude</category>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>Good DevOps Engineers Leave Trails Not Gates</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/deeheber/good-devops-engineers-leave-trails-not-gates-11hp</link>
      <guid>https://dev.to/deeheber/good-devops-engineers-leave-trails-not-gates-11hp</guid>
      <description>&lt;p&gt;I find it ironic that I officially hold the title of DevOps Engineer, because I've always believed DevOps wasn't meant to be a job title.&lt;/p&gt;

&lt;p&gt;DevOps is a philosophy. It's a culture of collaboration, shared ownership, and breaking down silos, not building new ones. Putting it on a business card was always a little counterintuitive to me.&lt;/p&gt;

&lt;p&gt;That distinction shapes a lot of how I think about this kind of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technical part is only half of it
&lt;/h2&gt;

&lt;p&gt;Platform engineering, SRE, DevOps, whatever you want to call it, the technical work matters. But so does the people and process side. In my experience that part is often underestimated. If the real problem is process, fix the process. Don't engineer around it.&lt;/p&gt;

&lt;p&gt;When someone on your team can't get what they need to do their job, that's worth a closer look. Is it a genuine security or compliance constraint? Totally valid, keep it. Is it unnecessary friction that could be removed? That's a choice someone made, and it can be unmade.&lt;/p&gt;

&lt;h2&gt;
  
  
  When enabling becomes gatekeeping
&lt;/h2&gt;

&lt;p&gt;Sometimes though, the role can slide into something else. This is especially common in mid to large sized companies where a separate team controls access to tools and systems. What starts as a reasonable org structure can quietly turn into unnecessary approval layers, access that takes weeks to get, and people feeling like they need to justify their technical decisions to someone outside their team.&lt;/p&gt;

&lt;p&gt;Picture this: a developer puts in a request for access to a tool they need to do their job. Instead of getting what they need, they find themselves defending their entire technical approach. Why are you doing it this way? Have you considered doing it that way instead? A simple request turns into an unsolicited code review from someone who likely doesn't have the full picture.&lt;/p&gt;

&lt;p&gt;A better approach is curiosity. When a request doesn't make sense, ask questions to understand the full picture before forming an opinion. There's usually context that isn't immediately visible. Listen, learn, then collaborate on the best path forward. The teams are different, but the goals are the same. Different function, not a higher one.&lt;/p&gt;

&lt;p&gt;If a developer's technical decisions are consistently missing the mark after feedback has been given, that's a conversation for their people manager to have, not a reason to build walls around everyone else's work.&lt;/p&gt;

&lt;h2&gt;
  
  
  You get to choose how you show up
&lt;/h2&gt;

&lt;p&gt;The best version of these roles is an enabler. Someone who clears the path, reduces unnecessary friction, and makes it easier for teammates to do their best work. Someone who treats good practices as something worth spreading across the whole team, not something to gatekeep.&lt;/p&gt;

&lt;p&gt;I love the outdoor principle of leaving the trail better than you found it. Don't make it harder for the next person. If you see something that needs fixing, fix it.&lt;/p&gt;

&lt;p&gt;Your job isn't to stand at the trailhead checking credentials. It's to make sure the trail is clear. That's a human centric approach to technical work, and in my opinion it's what separates the good ones from the great ones.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>team</category>
      <category>career</category>
      <category>collaboration</category>
    </item>
    <item>
      <title>I Rewrote My Step Function as a Durable Function</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sun, 01 Mar 2026 12:12:03 +0000</pubDate>
      <link>https://dev.to/aws-heroes/i-rewrote-my-step-function-as-a-durable-function-2je5</link>
      <guid>https://dev.to/aws-heroes/i-rewrote-my-step-function-as-a-durable-function-2je5</guid>
      <description>&lt;p&gt;Ever since AWS announced &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" rel="noopener noreferrer"&gt;Lambda durable functions&lt;/a&gt; at re:Invent 2025, I've been wanting to try them on a real project. Not a cookie cutter tutorial, but something where I could actually compare the two approaches. I already had the perfect candidate: my &lt;a href="https://github.com/deeheber/weather-site" rel="noopener noreferrer"&gt;weather site&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Background
&lt;/h2&gt;

&lt;p&gt;If you haven't read &lt;a href="https://dev.to/aws-builders/serverless-weather-reporting-with-aws-step-functions-and-cdk-8c8"&gt;my original blog post&lt;/a&gt;, here's the short version. I built &lt;a href="https://isitsnowinginhillsboro.com/" rel="noopener noreferrer"&gt;isitsnowinginhillsboro.com&lt;/a&gt; because the existing Portland snow site wasn't accurate for my area. It's a serverless workflow that checks the &lt;a href="https://openweathermap.org/api" rel="noopener noreferrer"&gt;OpenWeatherMap API&lt;/a&gt; every 10 minutes and updates a static S3 site with a YES or NO answer. The original uses a Step Function triggered by EventBridge Scheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rewrite It?
&lt;/h2&gt;

&lt;p&gt;I think a lot of us have been wondering when you'd pick durable functions over Step Functions. This project was small enough to rewrite quickly, but complex enough to exercise real patterns like API calls, branching logic, parallel execution, and multiple AWS services. Building the same thing both ways seemed like the best way to form my own opinion.&lt;/p&gt;

&lt;p&gt;The durable function version is &lt;a href="https://github.com/deeheber/durable-function-weather-site" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Two Approaches Compare
&lt;/h2&gt;

&lt;p&gt;The workflow logic is identical in both versions. Same end result. But the developer experience is pretty different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Functions
&lt;/h3&gt;

&lt;p&gt;You define your workflow as a state machine, chaining together states like &lt;code&gt;LambdaInvoke&lt;/code&gt;, &lt;code&gt;Choice&lt;/code&gt;, &lt;code&gt;Pass&lt;/code&gt;, and direct SDK integrations in CDK. The visual representation in the console is nice for understanding the flow at a glance, and it feels very "managed" in the best sense. The service handles state tracking, retries, and transitions for you.&lt;/p&gt;

&lt;p&gt;The tradeoff is that CDK code for Step Functions can get verbose. Passing data between states and setting up error handling means understanding how Step Functions manages its JSON payload. You're giving up some control for the convenience of the service doing the heavy lifting.&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%2F2ixqn0xhadfdekiocnig.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%2F2ixqn0xhadfdekiocnig.png" alt="step function view" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Durable functions
&lt;/h3&gt;

&lt;p&gt;With durable functions, you write your workflow as plain TypeScript. Wrap your logic in &lt;code&gt;ctx.step()&lt;/code&gt; calls, use regular &lt;code&gt;if&lt;/code&gt; statements for branching, &lt;code&gt;ctx.parallel()&lt;/code&gt; for parallel execution. Need to call an AWS service? Just use the SDK like you normally would inside a step.&lt;/p&gt;

&lt;p&gt;Here's the thing that surprised me: this version felt more natural to write. I wasn't thinking about "states" or "transitions." I was just writing code. Since it's TypeScript with a thin SDK wrapper, it also feels more portable. If another cloud provider or open source project adopted a similar checkpoint/replay pattern, the mental model (and probably a good chunk of the code) would transfer over.&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%2F70yk3vojbimcb4w6ty4u.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%2F70yk3vojbimcb4w6ty4u.png" alt="durable function view" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Side by Side
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Step Functions&lt;/th&gt;
&lt;th&gt;Durable functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Workflow definition&lt;/td&gt;
&lt;td&gt;JSON/YAML state machine (ASL)&lt;/td&gt;
&lt;td&gt;Plain TypeScript code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State management&lt;/td&gt;
&lt;td&gt;Managed by the service&lt;/td&gt;
&lt;td&gt;Automatic checkpointing via SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS service calls&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CallAwsService&lt;/code&gt; task or direct integration&lt;/td&gt;
&lt;td&gt;Regular AWS SDK calls inside &lt;code&gt;ctx.step()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP calls&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HttpInvoke&lt;/code&gt; task + Connection resource&lt;/td&gt;
&lt;td&gt;Standard &lt;code&gt;fetch()&lt;/code&gt; inside &lt;code&gt;ctx.step()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conditional logic&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Choice&lt;/code&gt; state&lt;/td&gt;
&lt;td&gt;Plain &lt;code&gt;if&lt;/code&gt; statement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel execution&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Parallel&lt;/code&gt; state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ctx.parallel([...])&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduling&lt;/td&gt;
&lt;td&gt;EventBridge Scheduler -&amp;gt; Step Function&lt;/td&gt;
&lt;td&gt;EventBridge Scheduler -&amp;gt; Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;State Machine + Connection + Lambda(s)&lt;/td&gt;
&lt;td&gt;Single Lambda function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;Step Function execution history (visual)&lt;/td&gt;
&lt;td&gt;Durable execution history&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Gotcha That Got Me
&lt;/h2&gt;

&lt;p&gt;Durable functions require a &lt;strong&gt;qualified ARN&lt;/strong&gt; for invocation, meaning a published version or alias. When I first wired up EventBridge Scheduler, I was using the unqualified ARN and couldn't figure out why it wasn't working.&lt;/p&gt;

&lt;p&gt;The issue? The CDK &lt;code&gt;LambdaInvoke&lt;/code&gt; scheduler target uses &lt;code&gt;functionArn&lt;/code&gt; under the hood, which for a plain &lt;code&gt;Function&lt;/code&gt; is the unqualified ARN — no version or alias suffix. Durable functions reject unqualified ARNs entirely.&lt;/p&gt;

&lt;p&gt;What ended up working was creating a Lambda alias in CDK and passing that to the scheduler target instead. Since an alias implements &lt;code&gt;IFunction&lt;/code&gt;, the construct picks up its qualified ARN automatically.&lt;/p&gt;

&lt;p&gt;If you're getting started with durable functions and things aren't behaving as expected, check your invocation ARN first.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Which One Should You Use?
&lt;/h2&gt;

&lt;p&gt;In my opinion, both approaches are solid for a workflow like this. It really comes down to developer experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you prefer writing workflows as code&lt;/strong&gt; , durable functions are going to feel great. The code reads like a normal application, the infrastructure footprint is smaller, and the patterns are more transferable if you ever need to move beyond AWS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you value visual debugging and a fully managed experience&lt;/strong&gt; , Step Functions has the edge right now. The console gives you a step-by-step view of every execution with clear status indicators. Durable functions have a visual for execution history too, but I prefer how Step Functions handles it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you need Distributed Map for massive fan-out scenarios&lt;/strong&gt; (up to 10,000 concurrent executions) or rely heavily on Step Functions' 220+ native service integrations, Step Functions is the better option.&lt;/p&gt;

&lt;p&gt;AWS also has &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-step-functions.html" rel="noopener noreferrer"&gt;official guidance&lt;/a&gt;. One thing I found interesting is they mention that hybrid architectures are totally valid, using durable functions for application-level logic while Step Functions handles higher-level cross-service coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;If you're curious about durable functions, I'd encourage trying it with a project you already have. You'll learn way more than a tutorial can teach you.&lt;/p&gt;

&lt;p&gt;Both repos are open source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step Functions version:&lt;/strong&gt; &lt;a href="https://github.com/deeheber/weather-site" rel="noopener noreferrer"&gt;github.com/deeheber/weather-site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durable functions version:&lt;/strong&gt; &lt;a href="https://github.com/deeheber/durable-function-weather-site" rel="noopener noreferrer"&gt;github.com/deeheber/durable-function-weather-site&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear from anyone else who's been experimenting with durable functions. Let me know what your experience has been! 🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>function</category>
      <category>lambda</category>
      <category>cdk</category>
    </item>
    <item>
      <title>Let an AI Agent Do Your Job Searching</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sun, 08 Feb 2026 09:12:03 +0000</pubDate>
      <link>https://dev.to/aws-heroes/let-an-ai-agent-do-your-job-searching-558a</link>
      <guid>https://dev.to/aws-heroes/let-an-ai-agent-do-your-job-searching-558a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@markuswinkler?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Markus Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-typewriter-with-a-job-application-printed-on-it-XKKuY4ottJ0?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Ff1dlvtuq5eu5we254tuq.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%2Ff1dlvtuq5eu5we254tuq.jpg" alt="Job Application Typewriter" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick disclaimer before I get into this: I'm no longer actively job hunting. I started building this project during my last job search and decided to finish what I started. Partly because I wanted to learn more about agents and partly because I think it might be useful for someone else out there. With that out of the way, here's the story.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Ever since I started my last job search, one thing kept bugging me. I had a list of "dream companies" that I wanted to work at, and I'd manually go check their career pages every few days to see if anything new popped up. Sometimes daily. Sometimes I'd forget for a week and miss a posting entirely.&lt;/p&gt;

&lt;p&gt;Here's the thing: job searching is already stressful enough without having to remember to check 10+ career pages on a regular cadence. I'd open a browser tab, search around, get distracted by Slack or email, and then forget where I left off. Multiply that by several companies and it becomes a real time sink.&lt;/p&gt;

&lt;p&gt;I kept thinking there has to be a better way. What if something could just watch those companies for me in the background and send me an email when there's an opening that matches what I'm looking for?&lt;/p&gt;

&lt;p&gt;That's when I decided to build it myself.&lt;/p&gt;

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

&lt;p&gt;The &lt;a href="https://github.com/deeheber/job-search-agent" rel="noopener noreferrer"&gt;job-search-agent&lt;/a&gt; is an AI agent built with &lt;a href="https://strandsagents.com" rel="noopener noreferrer"&gt;Strands Agents&lt;/a&gt; and deployed to &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html" rel="noopener noreferrer"&gt;Amazon Bedrock AgentCore Runtime&lt;/a&gt;. You give it a company name (and optionally a job title or location filter), and it searches the web for open positions at that company. Then it returns what it finds with links to the actual job postings.&lt;/p&gt;

&lt;p&gt;You can also set it up to run on a schedule and optionally send you email alerts when a company is hiring. That's the part I was most excited about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Decisions
&lt;/h2&gt;

&lt;p&gt;Here's how the architecture works at a high level:&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%2Fros1vxwejq6b1rhm2332.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%2Fros1vxwejq6b1rhm2332.png" alt="Job Search Architecture" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EventBridge Scheduler&lt;/strong&gt; kicks things off on whatever cadence you configure. This triggers the agent running in &lt;strong&gt;AgentCore Runtime&lt;/strong&gt; , which is where the Strands agent lives. The agent does its thing (searching for jobs at the companies you've specified), and if you've provided one or more email addresses in the environment variables and there is a job posting, it sends the results via &lt;strong&gt;SNS&lt;/strong&gt; as an email notification.&lt;/p&gt;

&lt;p&gt;The infrastructure is all defined in CDK (TypeScript), and the agent code is Python. I talked about why I use that particular combo in my &lt;a href="https://danielleheberling.xyz/blog/strands-agent-template/" rel="noopener noreferrer"&gt;strands-agent-template post&lt;/a&gt;, but the short version is that each framework is strongest in its native language right now.&lt;/p&gt;

&lt;p&gt;Is this a bit over-engineered for what it does? Most likely. But I wanted to use the opportunity to build something I'd actually use while learning about agents and AgentCore. In my experience, the best way to learn new tech is to solve a real problem with it, even if the solution is fancier than it needs to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;When I first started building this, I took what felt like the simplest approach. I put instructions in the agent's system prompt to construct the career page URLs for each company. Something along the lines of "for company X, try going to company.com/careers and look for job postings."&lt;/p&gt;

&lt;p&gt;This didn't work well at all.&lt;/p&gt;

&lt;p&gt;The agent would guess at URLs that didn't exist, hallucinate job listings, and burn through a ton of tokens trying to figure out where the careers page actually was. Some companies have their postings on Greenhouse. Others use Lever, Ashby, or their own custom systems. There's no standard for this, and asking an LLM to guess the right URL is a recipe for frustration.&lt;/p&gt;

&lt;p&gt;So I decided to build a tool for the agent to use instead. During that research, I came across &lt;a href="https://www.tavily.com/" rel="noopener noreferrer"&gt;Tavily&lt;/a&gt;, which is a search API built specifically for AI agents. Even better, Strands already had a pre-built Tavily tool available. I plugged it in, and the difference was night and day. Instead of guessing URLs, the agent now searches the web for actual career pages and job boards, then extracts the relevant information from those results.&lt;/p&gt;

&lt;p&gt;This was a good reminder for me that agents are only as useful as the tools you give them. The LLM is great at reasoning and formatting responses, but it shouldn't be doing the heavy lifting of web searching through prompt instructions alone.&lt;/p&gt;

&lt;p&gt;There was one more quirk worth mentioning. EventBridge Scheduler supports &lt;a href="https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html" rel="noopener noreferrer"&gt;universal targets&lt;/a&gt;, which let you call pretty much any AWS API action directly without needing a Lambda function in between. You just give it the service ARN and the request payload, and it makes the API call for you. There's a &lt;a href="https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html#unsupported-api-actions" rel="noopener noreferrer"&gt;list of unsupported action prefixes&lt;/a&gt; in the docs (things like &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;). Interestingly, &lt;code&gt;invokeModel&lt;/code&gt; is explicitly blocked, but &lt;code&gt;invokeAgentRuntime&lt;/code&gt; is not.&lt;/p&gt;

&lt;p&gt;So I set up EventBridge Scheduler to call the Bedrock AgentCore &lt;code&gt;invokeAgentRuntime&lt;/code&gt; action on a schedule. And it works. The agent gets invoked, does its thing, and returns results. But for some reason, EventBridge Scheduler &lt;em&gt;thinks&lt;/em&gt; the invocation failed. Every single time.&lt;/p&gt;

&lt;p&gt;If you leave retries enabled, the scheduler will retry the invocation multiple times even though the first call succeeded. That means your agent runs (and costs you money) three or four times instead of once. Also you may get duplicate email notifications. Not great.&lt;/p&gt;

&lt;p&gt;My workaround was to disable retries on the scheduler and set up a Dead Letter Queue (DLQ) to capture these "failed" invocations so I can monitor them. I'm honestly not sure if this is something I'm doing wrong or if it's a quirk on the AWS side that'll get fixed eventually. AgentCore is still pretty new, so it's possible this just hasn't been ironed out yet. If you've run into something similar, I'd love to hear about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Outcome
&lt;/h2&gt;

&lt;p&gt;After getting Tavily integrated, the agent started returning real job listings with real links. I set up EventBridge to run the searches on a schedule and configured SNS to email me the results.&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%2F9wx207v7wi6g0zg9h9oh.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%2F9wx207v7wi6g0zg9h9oh.png" alt="Job Search Results Email" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The time savings were immediately obvious. Instead of spending 30+ minutes bouncing between career pages every few days, I'd get an email in my inbox with a summary of who's hiring and links directly to the postings. Even when nothing new showed up, it was nice to not wonder if I'd missed something.&lt;/p&gt;

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

&lt;p&gt;If you decide to deploy this yourself, keep in mind that it will cost you money. Specifically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bedrock usage&lt;/strong&gt; is the main cost driver here. Every time the agent runs, it's making calls to a foundation model, and those tokens add up. How much depends on how many companies you're monitoring and how often the scheduler runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tavily&lt;/strong&gt; has a free tier that's pretty generous for personal use, but if you're running searches frequently or monitoring a lot of companies, you could exceed it. Keep an eye on your usage.&lt;/p&gt;

&lt;p&gt;I'd recommend starting with a low frequency schedule (maybe once a day or even once a week) and a small list of companies to get a feel for the costs before scaling up.&lt;/p&gt;

&lt;p&gt;Everything else in the stack (AgentCore Runtime, EventBridge Scheduler, SNS) will likely fall within the AWS free tier for personal use. But "likely" isn't a guarantee, so check the &lt;a href="https://aws.amazon.com/pricing/" rel="noopener noreferrer"&gt;pricing pages&lt;/a&gt; against the usage you expect before deploying.&lt;/p&gt;

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

&lt;p&gt;I think the biggest takeaway from this project is that building something you actually need is still the best way to learn new tech. I could have followed a tutorial to build a generic chatbot, but because this was solving a real problem for me, I was way more motivated to push through the frustrating parts.&lt;/p&gt;

&lt;p&gt;If you're curious about agents but not sure where to start, I'd suggest finding a small, annoying, repetitive task in your life and trying to automate it. It doesn't have to be fancy. The learning happens in the process of figuring out what works and what doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give It a Try
&lt;/h2&gt;

&lt;p&gt;The full source code is on &lt;a href="https://github.com/deeheber/job-search-agent" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. It includes instructions for running locally and deploying to AWS.&lt;/p&gt;

&lt;p&gt;If you're currently job hunting and this looks useful, take it for a spin. If you find bugs or have ideas for improvements, open an issue or submit a PR. I'm curious to hear what other folks build with it.&lt;/p&gt;

&lt;p&gt;Good luck out there 💪&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>aws</category>
      <category>tools</category>
    </item>
    <item>
      <title>A Strands Agent Template (For the Impatient)</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Fri, 23 Jan 2026 10:12:03 +0000</pubDate>
      <link>https://dev.to/aws-heroes/a-strands-agent-template-for-the-impatient-412j</link>
      <guid>https://dev.to/aws-heroes/a-strands-agent-template-for-the-impatient-412j</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%2Fgzltu4cbgie1px0jj2zh.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%2Fgzltu4cbgie1px0jj2zh.jpg" alt="Puzzle" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@ttepavac?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Tanja Tepavac&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-piece-of-a-puzzle-with-a-missing-piece-cWMhxNmQVq0?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ever since AWS announced &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html" rel="noopener noreferrer"&gt;Bedrock AgentCore Runtime&lt;/a&gt; back in July 2025, I've been experimenting with deploying agents to production. The hype around "agentic AI" is everywhere, but most examples I found were either too simple or way too complex for what I actually needed.&lt;/p&gt;

&lt;p&gt;Here's what I wanted 👉 a way to go from zero to a deployed agent on AWS without spending three days on infrastructure setup. So I built a template that does exactly that.&lt;/p&gt;

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

&lt;p&gt;The &lt;a href="https://github.com/deeheber/strands-agent-template" rel="noopener noreferrer"&gt;strands-agent-template&lt;/a&gt; repo is a GitHub template that gives you everything you need to deploy a &lt;a href="https://strandsagents.com/latest/" rel="noopener noreferrer"&gt;Strands agent&lt;/a&gt; to Amazon Bedrock AgentCore Runtime. Click "Use this template" and you're most of the way there.&lt;/p&gt;

&lt;p&gt;What's included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Production-ready CDK infrastructure with IAM, logging, and tracing&lt;/li&gt;
&lt;li&gt;✅ Local development setup so you can test before deploying&lt;/li&gt;
&lt;li&gt;✅ GitHub Actions for CI/CD&lt;/li&gt;
&lt;li&gt;✅ OpenTelemetry observability built in&lt;/li&gt;
&lt;li&gt;✅ Testing, linting, and formatting configured&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Python + TypeScript?
&lt;/h2&gt;

&lt;p&gt;I went with Python for the agent code and TypeScript for infrastructure. This isn't because I love context switching (I don't), but because each framework is strongest in its native language. Strands has great Python support and documentation, while CDK is cleanest in TypeScript.&lt;/p&gt;

&lt;p&gt;As these frameworks mature, I might consolidate to one language. But for now, this combo gives you access to the best libraries and examples for both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;If you just want to see it work after setting up the AWS CLI and configuring credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Test locally
cd agent &amp;amp;&amp;amp; source .venv/bin/activate &amp;amp;&amp;amp; python src/agentcore_app.py
# Test in another terminal
curl -X POST http://localhost:8080/invocations -H "Content-Type: application/json" -d '{"prompt": "What is 42 * 137?"}'
# Deploy to AWS
cd cdk &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm run build &amp;amp;&amp;amp; npm run cdk:deploy

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

&lt;/div&gt;



&lt;p&gt;The template comes with a basic example agent. Replace it with your own logic and you're done. Under 10 minutes from clone to deployed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Actually Get
&lt;/h2&gt;

&lt;p&gt;Here's what stood out to me after using this in a few projects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local testing that doesn't lie.&lt;/strong&gt; You can run your agent locally before deploying anything to AWS. This matters more than you'd think. I've wasted too much time debugging issues that only showed up after deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability without the extra work.&lt;/strong&gt; CloudWatch logs and OpenTelemetry tracing are configured out of the box. When something breaks (and it will), you can actually figure out why.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CI/CD that works.&lt;/strong&gt; GitHub Actions run your tests on every push. Both Python and TypeScript tooling is configured. It catches the obvious stuff before you deploy.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  If You're Just Getting Started
&lt;/h2&gt;

&lt;p&gt;If this is your first time deploying an agent to AWS, here's what I'd focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by running the example locally. Don't deploy anything yet. Get familiar with how Strands agents work.&lt;/li&gt;
&lt;li&gt;Then make a tiny change to the agent logic. See how it behaves. Break something on purpose and watch what happens.&lt;/li&gt;
&lt;li&gt;Only then deploy to AWS. Use the CloudWatch dashboard to see what your agent is actually doing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The template includes detailed deployment docs in the DEPLOYMENT.md file. I tried to write them for someone who hasn't used CDK or AgentCore before.&lt;/p&gt;

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

&lt;p&gt;I'm actively using this template for a few projects, so it'll keep evolving based on what I learn. If you find gaps or have suggestions, open an issue or submit a PR. The CONTRIBUTING.md file has guidelines.&lt;/p&gt;

&lt;p&gt;This is meant to be a starting point, not a finished product. Take it, modify it, make it yours.&lt;/p&gt;

&lt;p&gt;You can find the template on &lt;a href="https://github.com/deeheber/strands-agent-template" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know if you use it. I'm curious what works and what doesn't for other folks trying to deploy agents on AWS.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>aws</category>
      <category>agentcore</category>
    </item>
    <item>
      <title>Use Social Media Mindfully</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sat, 17 Jan 2026 10:12:03 +0000</pubDate>
      <link>https://dev.to/deeheber/use-social-media-mindfully-1596</link>
      <guid>https://dev.to/deeheber/use-social-media-mindfully-1596</guid>
      <description>&lt;p&gt;I quit Facebook in 2020 when a former coworker was spreading misinformation about what was happening in Portland, OR. He'd never been there and had no plans to visit. I was literally living in Portland at the time, telling him what I was seeing firsthand, but that didn't matter to him. That was it for me. I miss it sometimes, but mostly I don't.&lt;/p&gt;

&lt;p&gt;Here's what I've noticed since then: the heyday of social media feels like it's behind us. In my opinion, Facebook peaked in 2008. Back then, it was about connecting with friends, sharing actually interesting updates about our lives. Minimal ads. It felt genuine.&lt;/p&gt;

&lt;p&gt;Now? Wannabe influencers everywhere. More ads and brand accounts in your timeline than content from people you actually know. Bots running campaigns to get engagement through false things or distortions of reality. It's exhausting.&lt;/p&gt;

&lt;p&gt;But here's the thing: I'm not saying abandon social media entirely. I'm saying use it differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Think About Social Media Now
&lt;/h2&gt;

&lt;p&gt;I'm not scrolling feeds endlessly anymore. No traps of getting lost in reels or stories. I use &lt;a href="https://buffer.com/" rel="noopener noreferrer"&gt;Buffer&lt;/a&gt; to schedule posts, which keeps me from even looking at a timeline. I check in with intention when I need to, then I'm out. This one's harder than it sounds, but it makes a real difference in how much time you lose to these platforms.&lt;/p&gt;

&lt;p&gt;With that said, social media still works for connections. DMs are good. Having actual conversations in comments is good. Longer discussions where you're genuinely exchanging ideas? Even better. This is where I think the platforms still have value if you're intentional about it.&lt;/p&gt;

&lt;p&gt;I try to share things that might help someone else. Good articles I've read. Things I'm learning. Mistakes I've made. If it could save one person some time or frustration, it's worth sharing. The stuff you've learned the hard way, the patterns you're seeing in your day job...not to build a personal brand or chase engagement metrics, but because someone else is probably dealing with the same problems.&lt;/p&gt;

&lt;p&gt;If you're job hunting, LinkedIn especially can help you connect with the right people. It's not your whole career strategy, but it's a useful tool when you need it.&lt;/p&gt;

&lt;p&gt;Here's where I think we've lost the plot though: we've forgotten that coffee with friends to catch up beats any social media interaction. Travel somewhere to see people you care about. Those face-to-face conversations are what actually matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;For me, this means I spend my time learning, reading, and building things. When I do post, it's usually because I want to hear what other people think about something I'm working through. Or I've hit a problem that took me way too long to solve and I figure sharing it might save someone else the trouble.&lt;/p&gt;

&lt;p&gt;I'm not trying to go viral. I'm not optimizing for engagement. I'm definitely not checking how many likes something got.&lt;/p&gt;

&lt;p&gt;The goal is simple: be helpful. Connect with people who are thinking about similar problems. Have real conversations, even if they happen in threads or comment sections. That's what matters and what I'm focused on in 2026.&lt;/p&gt;

&lt;p&gt;Spend your time learning, reading, and building things. Use social media when it serves a purpose. Skip it when it doesn't.&lt;/p&gt;

&lt;p&gt;What's your approach? I'd be curious to hear how other people are thinking about this stuff.&lt;/p&gt;

</description>
      <category>community</category>
      <category>socialmedia</category>
      <category>internet</category>
      <category>communication</category>
    </item>
    <item>
      <title>How You Do It Matters</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Wed, 19 Nov 2025 15:12:03 +0000</pubDate>
      <link>https://dev.to/deeheber/how-you-do-it-matters-3nhn</link>
      <guid>https://dev.to/deeheber/how-you-do-it-matters-3nhn</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%2Fig4e06t8qjx7cjeuxx0b.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%2Fig4e06t8qjx7cjeuxx0b.jpg" alt="Winding path" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@jack\_anstey?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Jack Anstey&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/aerial-photography-of-road-zS4lUqLEiNA?utm\_source=unsplash&amp;amp;utm\_medium=referral&amp;amp;utm\_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Looking back on my career, the connections and opportunities I value most weren't the result of optimizing for speed. They grew from taking the long view.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How&lt;/em&gt; you do it matters just as much as &lt;em&gt;what&lt;/em&gt; you do.&lt;/p&gt;

&lt;p&gt;Take professional networking, for example. I've found that showing up consistently to community events, contributing even when I don't need anything, has led to the most meaningful connections and opportunities. That might look like speaking at a meetup, volunteering to help organize one, reviewing someone's resume, or answering career questions in Slack. Similarly, I'm drawn to organizations where solving real user problems is at the heart of what we build.&lt;/p&gt;

&lt;p&gt;I once worked at a startup where the CEO's departing words really stuck with me. This man was far from perfect, but I enjoyed working with him professionally and did it twice, mostly because of our alignment on what matters.&lt;/p&gt;

&lt;p&gt;Here's what he said upon his departure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As you continue to grow without me, I'd ask you to keep one thing in mind: the way we do it matters. We haven't gotten here because we're the cleverest copywriters, the fastest programmers, or the slickest sales people. We don't work sixteen hour days, and we're not ruthless or cutthroat. We're kind. We care about each other. We bring out the best of each other's strengths, and we bridge each other's weaknesses. We create opportunities to experiment and take risks. We're humble. And we're better for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, pragmatic tradeoffs are part of the job. I can move fast when needed, whether that's shipping a quick fix to unblock progress or meeting a tight deadline. The key is being intentional: planning to address the root cause rather than letting temporary solutions pile up. It's about being honest with yourself and your team about what you're doing and why.&lt;/p&gt;

&lt;p&gt;In an age of viral videos for quick wins, I know it can be challenging to play the long game...but I encourage you to consider it.&lt;/p&gt;

&lt;p&gt;This approach has led me to opportunities and relationships I wouldn't trade for anything. If you're wondering whether it's worth it to take a more intentional approach - I'd say give it a shot and see where it takes you.&lt;/p&gt;

</description>
      <category>career</category>
      <category>networking</category>
      <category>community</category>
    </item>
    <item>
      <title>Learning Outside Your Specialty | Why I Got a Kubernetes Cert</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Sun, 12 Oct 2025 10:12:03 +0000</pubDate>
      <link>https://dev.to/deeheber/learning-outside-your-specialty-why-i-got-a-kubernetes-cert-5aj0</link>
      <guid>https://dev.to/deeheber/learning-outside-your-specialty-why-i-got-a-kubernetes-cert-5aj0</guid>
      <description>&lt;p&gt;Earlier this month I took the exam for the &lt;a href="https://training.linuxfoundation.org/certification/kubernetes-cloud-native-associate/" rel="noopener noreferrer"&gt;Kubernetes and Cloud Native Associate (KCNA) certification&lt;/a&gt; and passed.&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%2F2ph65226dyo9webtcptg.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%2F2ph65226dyo9webtcptg.png" alt="KCNA Badge" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After years of working in AWS Serverless, this raised some eyebrows. People asked: why?&lt;/p&gt;

&lt;p&gt;Here's the honest answer: I've passed on applying to jobs because I didn't know Kubernetes (K8s). That needed to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality of Job Postings
&lt;/h2&gt;

&lt;p&gt;Look at DevOps and platform engineering roles today. Many of them want AWS experience, serverless knowledge, AND K8s expertise. Not all, but enough that it's a pattern.&lt;/p&gt;

&lt;p&gt;Specializing deeply in serverless has been valuable for my career. But at some point, gaps in your knowledge start closing doors. When I'm scanning job postings and thinking "I could do this role, except for that one requirement," it's time to consider filling the gap.&lt;/p&gt;

&lt;p&gt;This isn't about chasing every new technology. It's about recognizing when a skill has become common enough in your field that not having it limits options.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Best Tool for the Job" Actually Means
&lt;/h2&gt;

&lt;p&gt;I still believe in "serverless first." But here's what I've learned: the best tool depends on context.&lt;/p&gt;

&lt;p&gt;At the end of the day, users care that what you build is reliable, works, and solves their problem. Unless they're an engineer or tech geek, they don't care if you used K8s or serverless. They care about the outcome.&lt;/p&gt;

&lt;p&gt;Tech decisions are made by people. People make choices based on their experiences and what they know. A lot of teams use K8s. Whether they "need" it is a value judgment that depends entirely on your perspective and experience. That's not what this post is about.&lt;/p&gt;

&lt;p&gt;What I've realized: if I'm working with a team that's chosen K8s, fighting against that to use serverless creates friction. Understanding their world helps me work with them effectively, even if I'd make different choices.&lt;/p&gt;

&lt;p&gt;This isn't about one technology being better than the other. It's about understanding enough of both to collaborate with different teams and make informed decisions when I do have a choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  K8s Is Complex, But Learnable
&lt;/h2&gt;

&lt;p&gt;People aren't wrong when they say K8s is complex. It is. There are a lot of moving parts.&lt;/p&gt;

&lt;p&gt;But here's what studying for the KCNA taught me: if you take the time to understand the components and how they fit together, it's not magic. It's learnable. Breaking it down into pieces makes it manageable.&lt;/p&gt;

&lt;p&gt;The complexity isn't a reason to avoid it. It's just a reason to approach it systematically.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Advice: Depth First, Then Breadth
&lt;/h2&gt;

&lt;p&gt;If someone asked me "should I learn K8s?" a year ago, I would have said: &lt;strong&gt;get really good at one thing first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Master the fundamentals of whatever stack you're working in. Build that depth. Then expand your toolbelt.&lt;/p&gt;

&lt;p&gt;Trying to learn everything at once means you'll be mediocre at many things instead of excellent at one. Depth first, breadth later.&lt;/p&gt;

&lt;p&gt;Disclaimer: this is what works for me. Your situation might be different, and that's okay.&lt;/p&gt;

&lt;p&gt;That's what this K8s certification represents for me. Not abandoning serverless or becoming a "K8s person." Just adding another tool to solve different problems.&lt;/p&gt;

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

&lt;p&gt;The plan is to complete the &lt;a href="https://cloudresumechallenge.dev/docs/extensions/kubernetes-challenge/" rel="noopener noreferrer"&gt;Kubernetes Resume Challenge&lt;/a&gt; and build some personal projects. The goal is practical knowledge, not just cert credentials.&lt;/p&gt;

&lt;p&gt;Honestly, it's been fun to be a beginner again.&lt;/p&gt;

&lt;p&gt;I'd love to hear from you: Have you learned outside your specialty? What pushed you to do it, and what did you learn in the process?&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>kubernetes</category>
      <category>containers</category>
      <category>certifications</category>
    </item>
    <item>
      <title>Most Valuable When Least Visible | The Security Paradox</title>
      <dc:creator>Danielle Heberling</dc:creator>
      <pubDate>Wed, 18 Jun 2025 10:12:03 +0000</pubDate>
      <link>https://dev.to/aws-heroes/most-valuable-when-least-visible-the-security-paradox-48nm</link>
      <guid>https://dev.to/aws-heroes/most-valuable-when-least-visible-the-security-paradox-48nm</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%2F8fboi04zi6afdsbfsod8.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%2F8fboi04zi6afdsbfsod8.jpg" alt="Computer Lock" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@flyd2069?utm\_content=creditCopyText&amp;amp;utm\_medium=referral&amp;amp;utm\_source=unsplash" rel="noopener noreferrer"&gt;FlyD&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/pink-and-silver-padlock-on-black-computer-keyboard-F7aZ8G7gGBQ?utm\_content=creditCopyText&amp;amp;utm\_medium=referral&amp;amp;utm\_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Tale as old as time: the friction between building out new features and the foundations necessary to deliver those features. By foundations, I'm referring to things such as but not limited to: security, testing, Continuous Integration/Continuous Delivery, observability, and Infrastructure as Code.&lt;/p&gt;

&lt;p&gt;Recently I attended &lt;a href="https://reinforce.awsevents.com/" rel="noopener noreferrer"&gt;AWS re:Inforce&lt;/a&gt;, an AWS security focused conference. Speaking with fellow attendees it was very common for people ask some variant of "how can I get people in my organization to care about security?"&lt;/p&gt;

&lt;p&gt;Disclaimer that I do not consider myself a security person™️, but I do champion security initiatives often. Security is everyone's responsibility. Sometimes in the real world people get excited about new features and forget about less visible things such as security.&lt;/p&gt;

&lt;p&gt;Here are some of my thoughts in the form of unsolicited advice on how I attempt to navigate this.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Just Do It
&lt;/h2&gt;

&lt;p&gt;If you work in an organization that gives you the freedom to allocate your time to projects beyond what is officially committed to in the sprint, just do it. Then once it's finished, you can share with your team what you did, how it works, and why it's important.&lt;/p&gt;

&lt;p&gt;It is often faster to just do it rather than spend the same amount of time asking for permission. Especially at smaller early stage startups, delivering results speak louder than words.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. View Yourself as an Enabler
&lt;/h2&gt;

&lt;p&gt;Security is often (and mistakenly) seen as an obstacle to rapid feature development. I suggest reframing the conversation to highlight how security actually empowers the team to deliver features more quickly.&lt;/p&gt;

&lt;p&gt;Many security measures may not seem urgent now, but by the time they are, it’s often too late. Focus on communicating the value of being proactive instead of reactive.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Learn Incentives
&lt;/h2&gt;

&lt;p&gt;Incentives influence our perspectives and priorities. Invest time in understanding key stakeholders, especially decision-makers, to learn what drives them and what matters most to them.&lt;/p&gt;

&lt;p&gt;This understanding will help you frame your arguments more effectively when proposing needs that don’t have the allure of a shiny new feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Get Involved in 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%2Fmzxu0vu9wyhoiiwvkfh4.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%2Fmzxu0vu9wyhoiiwvkfh4.jpg" alt="AWS Community at Reinforce" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As tech professionals, it’s easy to find ourselves working in silos within our organizations. But the more I connect with colleagues outside of my current company, the more I discover that the challenges I’m facing have often already been solved by someone else.&lt;/p&gt;

&lt;p&gt;Why reinvent the wheel when we can learn from each other’s experiences - and share our own insights to help others grow? Engage in conversations, exchange ideas, and don’t hesitate to ask questions, even if they seem basic. Often, those “simple” questions lead to the most valuable discussions and solutions.&lt;/p&gt;

&lt;p&gt;In person conferences aren't your thing? Shameless plug to check out the &lt;a href="https://www.believeinserverless.com/" rel="noopener noreferrer"&gt;Believe in Serverless Community on Discord&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Ultimately, trust is the foundation of successful software. When it’s present, it’s invisible; when it’s missing, it becomes impossible to ignore. Once broken, trust is incredibly difficult to rebuild—especially for early-stage startups still working to establish their reputation. If users can’t trust your product, they won’t use it.&lt;/p&gt;

&lt;p&gt;I’m not claiming to have all the answers when it comes to security, but I hope sharing these thoughts sparks reflection or helps someone else feel less alone in facing these challenges. Your efforts to prioritize security truly matter, even when they go unseen. Keep pushing forward and championing the importance of strong foundations.&lt;/p&gt;

&lt;p&gt;I’d love to hear from you: What strategies or insights have helped you balance the tension between shipping new features and building secure, reliable products? &lt;br&gt; &lt;br&gt;&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>security</category>
      <category>community</category>
    </item>
  </channel>
</rss>
