<?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: Saurabh "Rob" Dahal</title>
    <description>The latest articles on DEV Community by Saurabh "Rob" Dahal (@raabdahl).</description>
    <link>https://dev.to/raabdahl</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%2F3709480%2F8d520395-4d17-449e-a5db-9dd63f9c5f62.jpeg</url>
      <title>DEV Community: Saurabh "Rob" Dahal</title>
      <link>https://dev.to/raabdahl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raabdahl"/>
    <language>en</language>
    <item>
      <title>Help Your Coding Assistant Find the Right Code in Large Repos</title>
      <dc:creator>Saurabh "Rob" Dahal</dc:creator>
      <pubDate>Fri, 16 Oct 2026 16:53:48 +0000</pubDate>
      <link>https://dev.to/raabdahl/help-your-coding-assistant-find-the-right-code-in-large-repos-20e3</link>
      <guid>https://dev.to/raabdahl/help-your-coding-assistant-find-the-right-code-in-large-repos-20e3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Get the starter:&lt;/strong&gt; &lt;a href="https://github.com/sdahal1/repo-search-workshop" rel="noopener noreferrer"&gt;sdahal1/repo-search-workshop on GitHub&lt;/a&gt;. The reproduction, searches, tests, and typecheck were rehearsed locally on October 16, 2026, with Node.js 24.10.0, npm 11.6.0, ripgrep 15.2.0, and ast-grep 0.51.0. The published repository was cloned and its starter revision verified. The supplied local folder and Git bundle also work for this guide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; Saurabh Rob Dahal, Developer Advocate, AWS&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Description:&lt;/strong&gt; Investigate a TypeScript retry bug using repository mapping, ripgrep, ast-grep, symbol navigation, and an evidence note you can use with different coding assistants.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Level:&lt;/strong&gt; Beginner · &lt;strong&gt;Time:&lt;/strong&gt; 60 minutes with a facilitator, after setup&lt;/p&gt;

&lt;p&gt;A coding assistant can suggest a plausible fix before it understands a repository. A useful investigation makes its reasoning checkable: where does the behavior live, what evidence explains it, and which checks would distinguish a correct fix from a partial one?&lt;/p&gt;

&lt;p&gt;In this workshop, you will investigate one prepared bug. A client configured with &lt;code&gt;maxRetries: 0&lt;/code&gt; still makes three requests when its transport fails. You will follow that setting across files, ask an assistant for a supported explanation, and make a small change.&lt;/p&gt;

&lt;p&gt;The bug is deliberately small. The practice is learning how to approach unfamiliar code without reading every file or accepting the first plausible explanation. The same approach is useful when an application setting behaves unexpectedly, a wrapper changes an argument, or an error originates in another package.&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%2Fa6l5g3b2lbb3vm1ea75q.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%2Fa6l5g3b2lbb3vm1ea75q.png" alt="The eight investigation steps progress from reproduce and map through text search, structural search, symbol navigation, evidence, explanation, and verification." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Each step answers a different question. If the evidence is incomplete, return to a focused lookup before editing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fydb3h3c07v7ja54rjwkd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fydb3h3c07v7ja54rjwkd.gif" alt="View the animated investigation sequence" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can follow along with Kiro, Codex, Claude Code, or another assistant that can read your project, run shell commands, and edit files. Choose a coding model supported by your tool. The exercise uses ordinary commands and a Markdown note, so it does not depend on a particular model, context window, or project-memory format.&lt;/p&gt;

&lt;p&gt;Your editor supplies definition and reference navigation. No AWS account, credentials, or cloud deployment is required. If you are working independently, pause at the evaluation prompts and take the time you need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Before the workshop
&lt;/h2&gt;

&lt;p&gt;You need Git, Node.js 24 with npm, ripgrep, and an editor with TypeScript definition and reference navigation. You should be comfortable opening a terminal and editing a text file. Complete your chosen assistant's sign-in before the session.&lt;/p&gt;

&lt;p&gt;The commands use a Bash-compatible shell: Terminal on macOS, a Linux terminal, or WSL on Windows. Run commands from the repository root unless a step says otherwise. Copy the contents of a command block without adding a leading &lt;code&gt;$&lt;/code&gt; prompt.&lt;/p&gt;

&lt;p&gt;Install ripgrep using the &lt;a href="https://github.com/BurntSushi/ripgrep#installation" rel="noopener noreferrer"&gt;official installation instructions&lt;/a&gt;. On a Mac with Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;ripgrep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a fresh checkout. Choose &lt;strong&gt;one&lt;/strong&gt; of these routes, then run the shared setup below. Clone the &lt;a href="https://github.com/sdahal1/repo-search-workshop" rel="noopener noreferrer"&gt;workshop starter repository&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/sdahal1/repo-search-workshop.git repo-search-workshop
&lt;span class="nb"&gt;cd &lt;/span&gt;repo-search-workshop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have the supplied local folder, skip cloning and enter it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;repo-search-workshop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have &lt;code&gt;repo-search-workshop.bundle&lt;/code&gt; in your current directory, create a checkout from that local Git bundle instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--branch&lt;/span&gt; starter ./repo-search-workshop.bundle repo-search-workshop
&lt;span class="nb"&gt;cd &lt;/span&gt;repo-search-workshop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the repository root, pin the workshop's starter revision and install its dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;--detach&lt;/span&gt; 5280be1e6659942e2335b10bde88b1fccdf9b76d
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; workshop/my-investigation
node &lt;span class="nt"&gt;--version&lt;/span&gt;
npm &lt;span class="nt"&gt;--version&lt;/span&gt;
rg &lt;span class="nt"&gt;--version&lt;/span&gt;
npm ci
npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; ast-grep &lt;span class="nt"&gt;--version&lt;/span&gt;
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checkout puts everyone on the same source revision. The new branch gives you a place to keep your work. The starter pins &lt;code&gt;@ast-grep/cli&lt;/code&gt; to 0.51.0 as a development dependency. &lt;code&gt;npm ci&lt;/code&gt; installs dependencies from the committed lockfile without updating it. &lt;a href="https://docs.npmjs.com/cli/v11/commands/npm-ci/" rel="noopener noreferrer"&gt;npm ci documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check your setup:&lt;/strong&gt; Node should report version 24, ast-grep should report 0.51.0, and &lt;code&gt;git status --short&lt;/code&gt; should produce no output in this fresh checkout. Open the entire repository folder in your editor so it can find the TypeScript project configuration.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;npx&lt;/code&gt; commands use the installed project executable. If npm offers to download a package, stop and check that installation succeeded and that you are in the repository root.&lt;/p&gt;

&lt;p&gt;The starter provides a fake transport, a failing regression test, an investigation template, and a saved AST rule. A transport is the component that performs the underlying request. Here, a small local function stands in for it, records calls, and fails predictably. No real service is involved.&lt;/p&gt;

&lt;p&gt;You may type each command yourself or ask the assistant to run the exact command. For the first pass, run the searches yourself so you can connect their inputs to their results. Later, delegate those same steps with an explicit scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 Show the failure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 0–4 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A reproduction turns a report into an observable difference between expected and actual behavior. It also gives you a check to run after editing.&lt;/p&gt;

&lt;p&gt;The report says: “I set &lt;code&gt;maxRetries&lt;/code&gt; to zero, but the client still retries.” Before investigating, define what counts as a retry. In this project, it is an additional attempt after the initial request. Therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total attempts when every request fails = 1 + allowed retries
zero retries = one initial attempt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq9q0beok2zoyetmzvzks.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%2Fq9q0beok2zoyetmzvzks.png" alt="A client configured with zero retries should make one initial request, but the prepared bug makes that request plus two additional attempts." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Count transport calls, including the initial request. The symptom does not yet tell us which function is responsible.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Run the demo, then the focused test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run demo
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:repro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected result before the fix:&lt;/strong&gt; The demo records three transport calls for &lt;code&gt;maxRetries: 0&lt;/code&gt;. The focused test fails because it expects one call and observes three. A failing assertion is intentional here; a missing-module or command-not-found error is a setup problem.&lt;/p&gt;

&lt;p&gt;The local rehearsal confirmed this failure. The full starter suite ran 11 tests: 10 passed, and only the zero-retries reproduction failed. Typechecking passed before the fix, showing that this behavioral bug is not a type error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Open &lt;code&gt;packages/client/test/client.test.ts&lt;/code&gt;. Find where the test supplies zero to the public client API, where the fake transport increments its counter, and where the test checks the final count. Confirm that the test observes behavior through the public API rather than directly testing a helper expression.&lt;/p&gt;

&lt;p&gt;Write the reproduction command, expected count, and actual count in &lt;code&gt;workshop/INVESTIGATION.md&lt;/code&gt;. Do not change an assertion to match the current behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; “The transport ran three times” is evidence. “The retry loop is off by one” is a hypothesis. Other explanations are possible: the option might be dropped, defaulted incorrectly, or interpreted differently. Keep those possibilities open until you trace the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 Map the repository
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 4–12 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A repository map identifies responsibilities and boundaries. It helps you choose where to look before spending time on implementation details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git ls-files
git ls-files &lt;span class="s1"&gt;'README*'&lt;/span&gt; &lt;span class="s1"&gt;'*package.json'&lt;/span&gt; &lt;span class="s1"&gt;'*tsconfig*.json'&lt;/span&gt;
git ls-files &lt;span class="s1"&gt;'packages/client/*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command shows tracked paths. The next commands narrow that inventory to project descriptions, manifests, TypeScript configuration, and the client package. Quoting the patterns passes them to Git instead of asking the shell to expand them. &lt;a href="https://git-scm.com/docs/git-ls-files" rel="noopener noreferrer"&gt;git ls-files documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;README.md&lt;/code&gt;, the root &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;packages/client/package.json&lt;/code&gt;, and &lt;code&gt;docs/client-options.md&lt;/code&gt;. Find the test scripts and the meaning of &lt;code&gt;maxRetries&lt;/code&gt;. A manifest describes a package's dependencies, scripts, and entry points; it helps connect a folder to what the project runs.&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%2Fu8oxnyubg91xqazjfsb9.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%2Fu8oxnyubg91xqazjfsb9.png" alt="The starter repository map separates root configuration, option documentation, client source and tests, and the workshop investigation files." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Use the map to choose a starting area. The relationships must still be confirmed in source and tests.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ask your assistant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map this repository using its tracked file paths, README, package
manifests, and docs/client-options.md. Do not edit files.

Identify the package most likely to own the reported retry behavior.
Explain your choice using paths and documented responsibilities.
Do not read every implementation file yet.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected result:&lt;/strong&gt; &lt;code&gt;packages/client&lt;/code&gt; is the likely owner. Its &lt;code&gt;src&lt;/code&gt; directory contains implementation and its &lt;code&gt;test&lt;/code&gt; directory contains the reproduction. The option documentation establishes that zero is valid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Write one sentence explaining why the client package is relevant. “It has client in its name” is a starting clue. A documented responsibility and a reproduction that imports the package are stronger support.&lt;/p&gt;

&lt;p&gt;Also identify the package's test command before editing. That prevents the assistant from guessing how the project is verified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; A map is a working hypothesis about ownership. Expand your scope if imports lead elsewhere. &lt;code&gt;git ls-files&lt;/code&gt; is an inventory of tracked files; it does not include every untracked file on disk, and it does not describe runtime behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 Search by text
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 12–18 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; Text search is useful when you know a name, error, or literal value. It finds mentions in code, tests, comments, and documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Search the owning package and option documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s1"&gt;'maxRetries'&lt;/span&gt; packages/client docs/client-options.md
rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; 3 &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s1"&gt;'maxRetries'&lt;/span&gt; packages/client/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rg&lt;/code&gt; runs ripgrep. &lt;code&gt;-n&lt;/code&gt; displays line numbers, &lt;code&gt;-F&lt;/code&gt; treats the query as literal text, and &lt;code&gt;-C 3&lt;/code&gt; includes three surrounding lines. The final arguments select where to search. &lt;a href="https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md" rel="noopener noreferrer"&gt;ripgrep guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected result:&lt;/strong&gt; Matches lead to the option type, request path, retry implementation, and regression test. Read a result as a location to inspect, not a complete explanation. Open the enclosing function when three surrounding lines are insufficient.&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%2F6bqnvbee0bppe0k5k9cg.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%2F6bqnvbee0bppe0k5k9cg.png" alt="Three search approaches answer different questions: text finds mentions, AST search finds syntax shapes, and symbol navigation resolves definitions and references." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Choose the search that matches your question. These tools complement one another throughout an investigation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Classify useful matches by their role:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kind of match&lt;/th&gt;
&lt;th&gt;What to learn from it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Option definition&lt;/td&gt;
&lt;td&gt;Which values the API accepts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caller or wrapper&lt;/td&gt;
&lt;td&gt;Whether the value is forwarded or transformed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;How the value affects behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test&lt;/td&gt;
&lt;td&gt;Which behavior is asserted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;What behavior is promised&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Add useful paths and symbols to your investigation note. Record actual line numbers from your checkout; the article does not prescribe fixed line numbers.&lt;/p&gt;

&lt;p&gt;If the search returns nothing, first check spelling, case, and your directory. A zero-result search means no matching text was found in the searched scope. It does not prove the behavior is absent from the program.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; A matching name does not establish a call relationship. Two modules may declare independent variables with the same spelling. Text search finds candidates; symbol navigation will help you distinguish them.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Search by structure
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 18–23 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; An abstract syntax tree, or AST, represents code through syntax nodes and their relationships. An expression such as &lt;code&gt;left || right&lt;/code&gt; has an operator and two operands. Structural search asks for that arrangement while allowing selected parts to vary. &lt;a href="https://ast-grep.github.io/advanced/core-concepts.html" rel="noopener noreferrer"&gt;ast-grep core concepts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You already know the option's name. Now ask a second question: where does the code use an OR expression that might supply a fallback? This is useful when the same structure appears under different variable names or across multiple lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Start with the operator as literal text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s1"&gt;'||'&lt;/span&gt; packages/client/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;-F&lt;/code&gt;: the pipe character has special meaning in regular expressions. Then run the prepared structural query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; ast-grep run &lt;span class="nt"&gt;--lang&lt;/span&gt; ts &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s1"&gt;'$VALUE || $FALLBACK'&lt;/span&gt; packages/client/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;run&lt;/code&gt; performs a one-time search, &lt;code&gt;--lang ts&lt;/code&gt; selects TypeScript, and &lt;code&gt;--pattern&lt;/code&gt; supplies the code shape. There is no rewrite argument, so this command does not modify code. &lt;a href="https://ast-grep.github.io/reference/cli/run.html" rel="noopener noreferrer"&gt;ast-grep run reference&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand the placeholders
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;$VALUE&lt;/code&gt; and &lt;code&gt;$FALLBACK&lt;/code&gt; are metavariables that match syntax nodes. Leave those names in the command. Keep the single quotes so the shell passes the dollar signs unchanged instead of expanding shell variables. &lt;a href="https://ast-grep.github.io/guide/quick-start.html" rel="noopener noreferrer"&gt;ast-grep quick start&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this candidate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MAX_RETRIES&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the left capture is &lt;code&gt;options.maxRetries&lt;/code&gt; and the right capture is &lt;code&gt;DEFAULT_MAX_RETRIES&lt;/code&gt;. The names &lt;code&gt;VALUE&lt;/code&gt; and &lt;code&gt;FALLBACK&lt;/code&gt; are labels we chose; they do not tell ast-grep what the author intended.&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%2F5742uow4l6t05rtqic13.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%2F5742uow4l6t05rtqic13.png" alt="An OR expression has a left operand captured by VALUE and a right operand captured by FALLBACK; the example captures options.maxRetries and DEFAULT_MAX_RETRIES." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The simplified tree shows what stays fixed—the OR operator—and what the metavariables can capture.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare matches and counterexamples
&lt;/h3&gt;

&lt;p&gt;Consider these illustrative snippets. They explain the pattern; they are not claimed to be exact starter files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MAX_RETRIES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeoutMs&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isOwner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// options.maxRetries || DEFAULT_MAX_RETRIES&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;explanation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options.maxRetries || DEFAULT_MAX_RETRIES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isReady&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The broad pattern matches the OR expressions assigned to &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;allowed&lt;/code&gt;. The multiline expression still has the requested shape. The comment and string are not executable OR expressions, and the final expression uses a different operator. &lt;a href="https://ast-grep.github.io/guide/pattern-syntax.html" rel="noopener noreferrer"&gt;ast-grep pattern syntax&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;isAdmin || isOwner&lt;/code&gt; is a valuable counterexample: it matches, but the boolean logic may be entirely correct. A syntax match is not a bug diagnosis. The tool does not know whether zero is meaningful to this particular API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Narrow and save the query
&lt;/h3&gt;

&lt;p&gt;Require the property name while leaving the object and right-hand expression variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; ast-grep run &lt;span class="nt"&gt;--lang&lt;/span&gt; ts &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s1"&gt;'$OPTIONS.maxRetries || $FALLBACK'&lt;/span&gt; packages/client/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected result:&lt;/strong&gt; The candidate in &lt;code&gt;packages/client/src/retry.ts&lt;/code&gt; remains. The object name can vary, so &lt;code&gt;config.maxRetries || 2&lt;/code&gt; also matches. However, this narrower pattern would miss &lt;code&gt;options['maxRetries'] || 2&lt;/code&gt; or a property read first assigned to a local variable. That is a reason to inspect the surrounding code, not a reason to search every possible expression at once.&lt;/p&gt;

&lt;p&gt;The starter's &lt;code&gt;workshop/defaulting.yml&lt;/code&gt; saves the broad query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;find-or-expressions&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$VALUE || $FALLBACK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; ast-grep scan &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rule&lt;/span&gt; workshop/defaulting.yml packages/client/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule gives the query a name and language so someone else can repeat it. &lt;a href="https://ast-grep.github.io/guide/rule-config" rel="noopener noreferrer"&gt;ast-grep rule essentials&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the pinned starter, the broad query returns four candidates: the multiline request-label expression, the trace expression, the retry-input validation condition, and the retry-setting expression. The first three implement intentional behavior. The narrowed query returns only the candidate in &lt;code&gt;retry.ts&lt;/code&gt;. Compare these results with the literal text search, which also finds mentions inside a comment and a string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Explain why each relevant match deserves inspection. Compare what text search found with what the structural query found. Save the candidate and its enclosing symbol in your note.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; Structural search reduces ambiguity about code shape. It does not establish runtime values, symbol identity, or business intent. Those need different evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Follow the symbols
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 23–28 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; Symbol navigation resolves an identifier to its declaration and finds uses of that declaration. It helps answer which function is actually involved when names repeat or imports are renamed.&lt;/p&gt;

&lt;p&gt;For example, a module could import &lt;code&gt;withRetry&lt;/code&gt; as &lt;code&gt;runWithRetries&lt;/code&gt;. Searching only for the original name might find the import but miss calls written with the alias. Definition navigation can connect those uses through the project language service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; In your editor:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the reproduction test and use &lt;strong&gt;Go to Definition&lt;/strong&gt; on &lt;code&gt;createClient&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;packages/client/src/client.ts&lt;/code&gt;, locate the request path and the call to &lt;code&gt;withRetry&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Go to Definition&lt;/strong&gt; on &lt;code&gt;withRetry&lt;/code&gt; to reach &lt;code&gt;packages/client/src/retry.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Find References&lt;/strong&gt; on its definition to inspect the callers.&lt;/li&gt;
&lt;li&gt;Inspect &lt;code&gt;ClientOptions&lt;/code&gt; in &lt;code&gt;packages/client/src/types.ts&lt;/code&gt; and compare it with the documented contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use the editor's context menu or command palette to find these actions. The names and shortcuts can differ; for one concrete implementation, see &lt;a href="https://code.visualstudio.com/docs/languages/typescript#_code-navigation" rel="noopener noreferrer"&gt;TypeScript navigation in Visual Studio Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi3ac7b52rat8uidb7f2z.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%2Fi3ac7b52rat8uidb7f2z.png" alt="The starter's symbol path connects the reproduction test to createClient and its request method, then withRetry, with ClientOptions providing the option contract." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Confirm the arrows by navigating definitions and inspecting callers. The picture illustrates the starter's relationships; it is not a screenshot or a generated runtime trace.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected result:&lt;/strong&gt; You can follow the option from the public client API to the retry implementation. Check whether the wrapper forwards zero unchanged before interpreting the defaulting expression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Record the caller and callee paths and symbols. A reference result may be a declaration, import, or call. Read it before recording a call relationship. Navigation also does not prove that a branch executed during the reproduction; combine it with the test and implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; Language Server Protocol, or LSP, standardizes communication for code intelligence. Editors can also provide TypeScript navigation through their own language-service integrations. The shared requirement here is working definition/reference navigation. There is no universal &lt;code&gt;lsp&lt;/code&gt; terminal command, and your assistant does not need direct LSP access. &lt;a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/" rel="noopener noreferrer"&gt;LSP specification&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6 Gather evidence before asking for a fix
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 28–36 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A short investigation note separates observations from interpretations and makes your context portable. Another assistant or teammate can inspect the same evidence without reconstructing a long conversation.&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%2F72l5fpp24t4ie41bgpac.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%2F72l5fpp24t4ie41bgpac.png" alt="An investigation note brings together the observed failure, repository owner, relevant symbols and paths, constraints, open hypothesis, proposed edits, and verification commands." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep the evidence compact enough to review, but specific enough to reproduce and challenge.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Complete &lt;code&gt;workshop/INVESTIGATION.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="gu"&gt;## Observed behavior&lt;/span&gt;
Reproduction command:
Expected behavior:
Actual behavior:

&lt;span class="gu"&gt;## Repository area&lt;/span&gt;
Owning package and evidence:

&lt;span class="gu"&gt;## Relevant code&lt;/span&gt;
Paths, symbols, actual line numbers, and caller relationships:

&lt;span class="gu"&gt;## Constraints&lt;/span&gt;
Preserve the public API and omitted-option behavior.
Keep the fake transport and meaningful assertions.

&lt;span class="gu"&gt;## Root cause hypothesis&lt;/span&gt;
Leave blank until the next step.

&lt;span class="gu"&gt;## Proposed modification points&lt;/span&gt;
Leave blank until the next step.

&lt;span class="gu"&gt;## Verification&lt;/span&gt;
npm run test:repro
npm test
npm run typecheck
git status --short
git diff
git diff --check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An evidence entry might say, “The reproduction passes zero at the public API and observes three transport calls.” Attach the actual test location. A hypothesis would say, “A defaulting expression may replace zero before the loop runs.” Keeping these in different sections makes it easier to notice what remains unproven.&lt;/p&gt;

&lt;p&gt;Include a short reason beside each source location. “This wrapper forwards the option” is more useful than a list of six paths with no explanation. Leave out unrelated search results and large copied files; the assistant can open the referenced code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Could someone who missed the walkthrough reproduce the failure and locate the relevant expressions from your note? Could they tell which claims you observed and which still require checking?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; Good context is selected evidence with an explicit purpose. Paths and symbols help someone relocate it; line numbers identify positions in this checkout and may move after edits.&lt;/p&gt;

&lt;h2&gt;
  
  
  7 Explain the root cause before editing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 36–43 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A supported hypothesis connects the input, the transformation, and the observed output. Evaluate that connection before changing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; In a fresh or existing assistant conversation in the same checkout, paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read workshop/INVESTIGATION.md. Do not edit files.

Inspect the referenced code and explain the failing behavior.
If evidence is missing, identify the next focused lookup needed.

Return:
- Your root-cause hypothesis.
- Supporting paths, symbols, and actual line numbers.
- Any uncertainty or competing explanation.
- The smallest proposed change and expected modified files.
- Tests that distinguish a correct fix from a partial fix.

Stop before editing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may use a plan or read-only mode if your tool provides one. The explicit instruction is still useful because it tells the assistant what deliverable you want at this stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected explanation:&lt;/strong&gt; &lt;code&gt;0 || DEFAULT_MAX_RETRIES&lt;/code&gt; selects the default because zero is falsy. With a default of two retries, the always-failing transport receives one initial call plus two retries. The &lt;code&gt;??&lt;/code&gt; operator uses its fallback only for &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, preserving zero. &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing" rel="noopener noreferrer"&gt;TypeScript nullish coalescing documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbk7f58vy8ox2m5vdtfr6.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%2Fbk7f58vy8ox2m5vdtfr6.png" alt="A value table compares OR and nullish coalescing with fallback 2: zero becomes 2 under OR but remains zero under nullish coalescing; omitted values use the fallback." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The operator table explains language behavior. Its null, false, and empty-string examples do not expand the client's numeric input contract.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a text version of the diagram:&lt;/p&gt;

&lt;p&gt;| Left value (&lt;code&gt;x&lt;/code&gt;) | &lt;code&gt;x \|\| 2&lt;/code&gt; | &lt;code&gt;x ?? 2&lt;/code&gt; | API meaning here |&lt;br&gt;
| --- | --- | --- | --- |&lt;br&gt;
| &lt;code&gt;0&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | &lt;code&gt;0&lt;/code&gt; | Valid: disable retries |&lt;br&gt;
| &lt;code&gt;undefined&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | Omitted option: use the default |&lt;br&gt;
| &lt;code&gt;1&lt;/code&gt; | &lt;code&gt;1&lt;/code&gt; | &lt;code&gt;1&lt;/code&gt; | Valid: allow one retry |&lt;br&gt;
| &lt;code&gt;null&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | Language example, outside the option type |&lt;br&gt;
| &lt;code&gt;false&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | &lt;code&gt;false&lt;/code&gt; | Language example, outside the option type |&lt;br&gt;
| &lt;code&gt;''&lt;/code&gt; | &lt;code&gt;2&lt;/code&gt; | &lt;code&gt;''&lt;/code&gt; | Language example, outside the option type |&lt;/p&gt;

&lt;p&gt;Neither operator validates input. The proposed change corrects defaulting for values already allowed by the API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate:&lt;/strong&gt; Check three links in the explanation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The public contract allows zero, and the wrapper delivers it unchanged.&lt;/li&gt;
&lt;li&gt;The identified expression replaces zero with the documented default of two.&lt;/li&gt;
&lt;li&gt;The retry loop interprets two as additional attempts, producing three total calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If one link is missing, perform the next focused lookup. An answer that simply recommends &lt;code&gt;??&lt;/code&gt; has not yet explained the whole symptom. A proposed loop change also needs evidence that the loop itself is wrong.&lt;/p&gt;

&lt;p&gt;Optional self-check in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'console.log({ or: 0 || 2, nullish: 0 ?? 2 })'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected values are &lt;code&gt;or: 2&lt;/code&gt; and &lt;code&gt;nullish: 0&lt;/code&gt;. This checks language behavior in isolation; it does not prove the repository's value follows that path. The earlier evidence establishes that connection.&lt;/p&gt;

&lt;p&gt;Update the hypothesis and proposed modification sections of your note. Do not broaden the API to accept &lt;code&gt;null&lt;/code&gt;, strings, or booleans just because the operator table includes them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; Different models may phrase the explanation differently. Judge the evidence and predicted behavior. A useful hypothesis also tells you what you should observe after the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  8 Make the narrow change and verify it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 43–56 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A fix must correct the reported behavior and preserve the surrounding contract. Test results and diff review provide different parts of that evidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; After checking the explanation, tell the assistant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apply the smallest change supported by our investigation.
Preserve the public API and default retry behavior.
Keep the reproduction's original assertion intact.
Add focused regression coverage only where it is missing.
Do not refactor unrelated code or update dependencies.
Do not stage or commit the changes.
Run the verification commands in workshop/INVESTIGATION.md.
Report the modified files and actual results, including failures.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected production change is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- const retries = options.maxRetries || DEFAULT_MAX_RETRIES;
&lt;/span&gt;&lt;span class="gi"&gt;+ const retries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are editing manually, make the same justified change in the editor. Avoid a global replacement of &lt;code&gt;||&lt;/code&gt;: other matches may intentionally use boolean logic or falsy-value defaults.&lt;/p&gt;

&lt;p&gt;Run the checks yourself if the assistant has not run them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:repro
npm &lt;span class="nb"&gt;test
&lt;/span&gt;npm run typecheck
npm run demo
git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git diff
git diff &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Evaluate the behavior
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3w7940mbtptzifbckvz.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%2Fp3w7940mbtptzifbckvz.png" alt="A verification matrix checks zero, omitted, and positive retry settings against expected request counts and also checks immediate success. Separate checks cover types and diff scope." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A useful test matrix checks the repaired boundary and nearby behavior that should remain valid.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the fake transport failing on every attempt, verify:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Expected total transport calls after the fix&lt;/th&gt;
&lt;th&gt;Why check it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxRetries: 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Reproduces the reported boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Option omitted, default of 2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Preserves the default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxRetries: 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Preserves explicit positive values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Also preserve immediate success: when the first request succeeds, there should be one call, regardless of a larger retry allowance. A retry budget allows extra attempts after failure; it does not require them after success.&lt;/p&gt;

&lt;p&gt;The rehearsed solution passed the reproduction, all 11 tests, and typechecking; its demo showed one call for zero retries. Those are the expected results for your fix. Read the test output rather than accepting a summary that says “looks good.” Check which command ran and whether it completed successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluate the change
&lt;/h3&gt;

&lt;p&gt;Inspect every changed file. The investigation note is expected to change. Production edits should be limited to the justified implementation; test edits should strengthen coverage while preserving the reproduction's original assertion.&lt;/p&gt;

&lt;p&gt;Ask why any dependency lockfile, public type, unrelated helper, or large formatting block changed. Such edits need their own justification. Also inspect untracked files reported by &lt;code&gt;git status&lt;/code&gt;, because a normal diff does not display their contents.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git diff&lt;/code&gt; shows unstaged tracked changes. If you staged anything, also run &lt;code&gt;git diff --cached&lt;/code&gt;. &lt;code&gt;git diff --check&lt;/code&gt; checks whitespace errors; silence does not establish behavioral correctness. &lt;a href="https://git-scm.com/docs/git-diff" rel="noopener noreferrer"&gt;git diff documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teaching moment:&lt;/strong&gt; The reproduction checks the bug. Nearby tests check preserved behavior. Typechecking checks type compatibility. Diff review checks the scope and meaning of edits. A passing check cannot answer all four questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finish with a reusable investigation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time: 56–60 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Explain the bug to a partner in three sentences: what failed, where the value changed meaning, and how you verified the fix. Point to evidence for each sentence.&lt;/p&gt;

&lt;p&gt;Then name the question each tool answered. Text search found mentions. AST search found a code shape. Symbol navigation connected definitions and uses. Tests observed behavior. Your investigation note connected those findings into an explanation someone else could review.&lt;/p&gt;

&lt;p&gt;On your next unfamiliar repository, start with a reproducible symptom and a small map. Choose searches according to the question you need answered. Expand the scope when the evidence requires it, and give your assistant a clear boundary between investigating and editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  If a step behaves differently
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Next check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;rg&lt;/code&gt; is not found&lt;/td&gt;
&lt;td&gt;Install ripgrep, reopen the terminal, and run &lt;code&gt;rg --version&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ast-grep is missing or the version differs&lt;/td&gt;
&lt;td&gt;Return to the repository root; confirm &lt;code&gt;npm ci&lt;/code&gt; succeeded with development dependencies installed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AST search has no matches&lt;/td&gt;
&lt;td&gt;Check the directory, TypeScript language flag, and single quotes. Confirm you still have the unfixed starter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Definition navigation fails&lt;/td&gt;
&lt;td&gt;Open the repository root, install dependencies, and confirm the editor recognizes the TypeScript project. Follow imports manually while fixing navigation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The reproduction already passes&lt;/td&gt;
&lt;td&gt;Inspect the checkout and existing diff. You may have the solution or a previous edit. Preserve your work and use a fresh starter checkout.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A test reports a setup error&lt;/td&gt;
&lt;td&gt;Resolve that error before interpreting it as evidence of the retry bug.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The assistant edits during investigation&lt;/td&gt;
&lt;td&gt;Inspect the diff before continuing. Preserve your note and use a fresh starter checkout if needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fix passes one test but breaks another&lt;/td&gt;
&lt;td&gt;Compare the failing case with the documented contract; revisit the hypothesis instead of weakening an assertion.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No cloud resources are created by this exercise, so there is no AWS cleanup step. Keep your checkout to reuse the investigation note and commands.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>lsp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Setting up the Agent Toolkit for AWS in Kiro (and Codex, Claude Code, and Cursor)</title>
      <dc:creator>Saurabh "Rob" Dahal</dc:creator>
      <pubDate>Tue, 30 Jun 2026 12:59:54 +0000</pubDate>
      <link>https://dev.to/raabdahl/setting-up-the-agent-toolkit-for-aws-in-kiro-and-codex-claude-code-and-cursor-15e5</link>
      <guid>https://dev.to/raabdahl/setting-up-the-agent-toolkit-for-aws-in-kiro-and-codex-claude-code-and-cursor-15e5</guid>
      <description>&lt;p&gt;If you've let a coding agent loose on AWS, you've watched it guess. It invents API parameters that don't exist, or hands you an S3 bucket a security review will bounce on sight. The Agent Toolkit for AWS is built to stop that. By the end of this post you'll have it running in whatever editor you use, plus a tour of what's in it and three workflows worth pointing it at.&lt;/p&gt;

&lt;p&gt;I use Kiro day to day, so I'll walk through that setup first. It also works with Codex, Claude Code, Cursor, and any other agent that speaks MCP, the Model Context Protocol, which is the open standard agents use to connect to outside tools and data. I'll cover those too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Agent Toolkit for AWS?
&lt;/h2&gt;

&lt;p&gt;The Agent Toolkit for AWS is a free, AWS-supported set of tools that gives AI coding agents secure access to AWS, current documentation they can read mid-task, and tested procedures for the work they tend to fumble. It plugs into the agent you already use rather than asking you to switch. In practice, that shows up in a few ways, all detailed in the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;AWS user guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The agent stops guessing about APIs it never saw. The models behind these agents trained on data that's months or years old, so anything AWS shipped recently is missing or wrong in their heads, and the toolkit hands them current docs and references at request time. For multi-step work like least-privilege IAM or a production serverless stack, it follows a vetted skill instead of reconstructing the steps from half-memory. Every call goes through your own IAM credentials, shows up in CloudWatch, and gets logged to CloudTrail, so you can scope an agent to read-only even when your role can write. And the toolkit costs nothing on its own; you pay only for the AWS resources the agent creates.&lt;/p&gt;

&lt;p&gt;It's the successor to the MCP servers, skills, and plugins AWS shipped under &lt;a href="https://github.com/awslabs" rel="noopener noreferrer"&gt;AWS Labs&lt;/a&gt; in 2025. Two things make me reach for it over a raw MCP setup: condition keys that let a policy tell an agent apart from a human, and skills that have been evaluated end to end rather than thrown over the wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's included: the MCP server, skills, plugins, and rules files
&lt;/h2&gt;

&lt;p&gt;Four components work together (&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;reference&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The AWS MCP Server is the access layer, a single endpoint that reaches 300+ AWS services. It runs in two modes depending on what you ask for. Searching AWS docs, pulling service info, and discovering skills need no credentials at all, so the server is useful the moment you connect it. Anything that touches your account, real API calls and the sandboxed Python &lt;code&gt;run_script&lt;/code&gt; tool, runs as you through your local AWS credentials. It also stamps two condition keys on every request, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, so your policies can single out agent traffic.&lt;/p&gt;

&lt;p&gt;Skills are curated packages of instructions, scripts, and reference material for one task. The agent loads a skill only when it needs it, so they barely touch your context until they're relevant.&lt;/p&gt;

&lt;p&gt;Plugins bundle the MCP config and a curated skill set into one install. They're available for Claude Code, Codex, and Cursor; Kiro and other MCP agents connect to the server directly instead, which I cover in the setup steps below. Four ship today:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;Covers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Service selection, CDK/CloudFormation, serverless, containers, storage, observability, billing, SDK usage, deployment. &lt;strong&gt;Start here.&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-agents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Building AI agents on AWS with Amazon Bedrock and AgentCore.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-data-analytics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data lake, analytics, and ETL with S3 Tables, AWS Glue, and Athena.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-agents-for-devsecops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Incident investigation, code review, UAT, vulnerability scanning, and pen testing with AWS DevOps Agent and AWS Security Agent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rules files are project-level config that sets guardrails: use the MCP Server, find a skill before acting, check the docs, prefer infrastructure-as-code. Rules decide how the agent behaves; skills supply what it does for a given job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which skills does the Agent Toolkit include?
&lt;/h3&gt;

&lt;p&gt;The skills are the part I underestimated at first. There are around 64 today (browse the &lt;a href="https://github.com/aws/agent-toolkit-for-aws/tree/main/skills" rel="noopener noreferrer"&gt;&lt;code&gt;skills/&lt;/code&gt; directory&lt;/a&gt; for the live list), split into core and specialized.&lt;/p&gt;

&lt;p&gt;Core skills, which ship with &lt;code&gt;aws-core&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;amazon-bedrock&lt;/code&gt;, &lt;code&gt;aws-billing-and-cost-management&lt;/code&gt;, &lt;code&gt;aws-blocks&lt;/code&gt;, &lt;code&gt;aws-cdk&lt;/code&gt;, &lt;code&gt;aws-cloudformation&lt;/code&gt;, &lt;code&gt;aws-containers&lt;/code&gt;, &lt;code&gt;aws-iam&lt;/code&gt;, &lt;code&gt;aws-messaging-and-streaming&lt;/code&gt;, &lt;code&gt;aws-observability&lt;/code&gt;, &lt;code&gt;aws-sdk-js-v3-usage&lt;/code&gt;, &lt;code&gt;aws-sdk-python-usage&lt;/code&gt;, &lt;code&gt;aws-sdk-swift-usage&lt;/code&gt;, &lt;code&gt;aws-serverless&lt;/code&gt;, &lt;code&gt;signing-in-to-aws&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Specialized skills, grouped by domain (a few from each):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless (9)&lt;/strong&gt;: &lt;code&gt;connecting-lambda-to-api-gateway&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-dynamodb&lt;/code&gt;, &lt;code&gt;debugging-lambda-timeouts&lt;/code&gt;, &lt;code&gt;processing-s3-uploads-with-step-functions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics (10)&lt;/strong&gt;: &lt;code&gt;querying-data-lake&lt;/code&gt;, &lt;code&gt;ingesting-into-data-lake&lt;/code&gt;, &lt;code&gt;managing-amazon-msk&lt;/code&gt;, &lt;code&gt;amazon-opensearch-service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database (8)&lt;/strong&gt;: &lt;code&gt;amazon-aurora-postgresql&lt;/code&gt;, &lt;code&gt;amazon-elasticache&lt;/code&gt;, &lt;code&gt;exporting-rds-to-s3&lt;/code&gt;, &lt;code&gt;rds-db2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking (5)&lt;/strong&gt;: &lt;code&gt;creating-production-vpc-multi-az&lt;/code&gt;, &lt;code&gt;routing-traffic-with-route53-and-cloudfront&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage (5)&lt;/strong&gt;: &lt;code&gt;securing-s3-buckets&lt;/code&gt;, &lt;code&gt;creating-data-lake-table&lt;/code&gt;, &lt;code&gt;storing-and-querying-vectors&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 (3)&lt;/strong&gt;, &lt;strong&gt;Operations (3)&lt;/strong&gt;, &lt;strong&gt;System table (3)&lt;/strong&gt;, &lt;strong&gt;Migration (2)&lt;/strong&gt;, &lt;strong&gt;Security and identity (1)&lt;/strong&gt;, &lt;strong&gt;Web and mobile (1)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't memorize the list. When you ask for "a Lambda behind API Gateway writing to DynamoDB," the agent pulls the matching skills on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;A handful of things need to be in place first. None take long.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An AWS account.&lt;/strong&gt; Anything that touches AWS needs one. &lt;a href="https://docs.aws.amazon.com/accounts/latest/reference/getting-started.html" rel="noopener noreferrer"&gt;Sign up here&lt;/a&gt; if you don't have one yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS credentials on your machine&lt;/strong&gt;, for the parts that act on your account. The server still connects and answers documentation and skill questions without them, but API calls and &lt;code&gt;run_script&lt;/code&gt; need them. The proxy reads the standard AWS credential chain, so &lt;code&gt;aws configure&lt;/code&gt;, an SSO login, a named profile, or the usual environment variables all work. New to this? &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html" rel="noopener noreferrer"&gt;Configuring the AWS CLI&lt;/a&gt; is the simplest path. The CLI is the common way to set credentials, not a hard requirement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt;&lt;/strong&gt;, a Python package tool that runs the MCP proxy. Install it with &lt;code&gt;brew install uv&lt;/code&gt; on macOS, or the &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;official installer&lt;/a&gt; elsewhere. The &lt;code&gt;uvx&lt;/code&gt; command in the Kiro config below comes bundled with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;, which gives you the &lt;code&gt;npx&lt;/code&gt; command used to install skills. If &lt;code&gt;npx --version&lt;/code&gt; prints nothing, install it from &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;nodejs.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CLI &lt;code&gt;2.35.0&lt;/code&gt; or later&lt;/strong&gt;, but only if you use the one-command wizard below. Check with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to set up the Agent Toolkit for AWS
&lt;/h2&gt;

&lt;p&gt;The quickest route is the AWS CLI wizard, which configures every agent you have at once. Prefer to do it by hand, or only use one editor? Skip to the per-agent steps below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up every agent at once with the AWS CLI
&lt;/h3&gt;

&lt;p&gt;On a recent AWS CLI, one command detects your installed agents, installs default skills, and configures the MCP Server for all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure agent-toolkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha worth calling out, because I hit it. On an older CLI you'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws: [ERROR]: argument subcommand: Found invalid choice 'agent-toolkit'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means your AWS CLI predates &lt;code&gt;2.35.0&lt;/code&gt;. Update it (&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;instructions&lt;/a&gt;), confirm with &lt;code&gt;aws --version&lt;/code&gt;, and rerun. Restart your agent afterward so it picks up the new MCP config.&lt;/p&gt;

&lt;p&gt;If you only use one agent, or you want to see exactly what gets wired up, the per-agent steps below do the same thing by hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kiro
&lt;/h3&gt;

&lt;p&gt;Open your Kiro MCP config and add the AWS server. Use &lt;code&gt;.kiro/settings/mcp.json&lt;/code&gt; for the current project, or &lt;code&gt;~/.kiro/settings/mcp.json&lt;/code&gt; to turn it on everywhere. Create the file if it doesn't exist yet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aws"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-proxy-for-aws@1.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://aws-mcp.us-east-1.api.aws/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--metadata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS_REGION=us-west-2"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your config already lists other servers under &lt;code&gt;mcpServers&lt;/code&gt;, add the &lt;code&gt;aws&lt;/code&gt; entry next to them instead of replacing the block, and keep the JSON valid (mind the commas). Change &lt;code&gt;AWS_REGION&lt;/code&gt; to the region you work in.&lt;/p&gt;

&lt;p&gt;Pin the proxy version rather than tracking latest. You get reproducible behavior and a guard against a bad release. Check &lt;a href="https://pypi.org/project/mcp-proxy-for-aws/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; every few weeks and bump it on purpose.&lt;/p&gt;

&lt;p&gt;Then install the skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open Kiro's MCP Server view (the Kiro panel in the sidebar, or search "MCP" in the command palette), reconnect the &lt;code&gt;aws&lt;/code&gt; server, and you're live.&lt;/p&gt;

&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;Add the marketplace, then install from inside Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex plugin marketplace add aws/agent-toolkit-for-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch Codex, run &lt;code&gt;/plugins&lt;/code&gt;, and install &lt;code&gt;aws-core&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;The plugins live on the official Anthropic marketplace, included by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin install aws-core@claude-plugins-official
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hit &lt;code&gt;Plugin not found&lt;/code&gt;? Refresh the index with &lt;code&gt;/plugin marketplace update claude-plugins-official&lt;/code&gt; and try again. Add &lt;code&gt;aws-agents&lt;/code&gt;, &lt;code&gt;aws-data-analytics&lt;/code&gt;, or &lt;code&gt;aws-agents-for-devsecops&lt;/code&gt; the same way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;Add the repo as a team marketplace: &lt;strong&gt;Settings → Plugins → Team Marketplaces → Add Marketplace → Import from Repo&lt;/strong&gt;, pointed at &lt;code&gt;aws/agent-toolkit-for-aws&lt;/code&gt;. Open the &lt;strong&gt;Plugins&lt;/strong&gt; panel and install &lt;code&gt;aws-core&lt;/code&gt; first, then the others as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other agents (Windsurf, Cline, and more)
&lt;/h3&gt;

&lt;p&gt;Anything that speaks MCP works, including Windsurf and Cline. Configure the AWS MCP Server directly (see the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html" rel="noopener noreferrer"&gt;server setup guide&lt;/a&gt;), then run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I check it's working?
&lt;/h2&gt;

&lt;p&gt;Start a fresh conversation and ask: &lt;em&gt;"What AWS Regions are available?"&lt;/em&gt; If the agent returns a list, the MCP Server is connected. For a skill check, ask it to "secure an S3 bucket" and watch it load &lt;code&gt;securing-s3-buckets&lt;/code&gt; before it writes anything. An authentication error instead means your local credentials aren't reaching the server; see Prerequisites for how to set them up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three workflows that show the payoff
&lt;/h2&gt;

&lt;p&gt;Setup is the boring part. The workflows below are where it pays off, and each one names the skills and components doing the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Stand up a serverless API, end to end
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"Build a REST API: API Gateway in front of a Lambda that reads and writes a DynamoDB table, deployed with CDK."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the kind of task agents usually botch, because it spans four services and the IAM glue between them. The agent pulls &lt;code&gt;aws-serverless&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-api-gateway&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-dynamodb&lt;/code&gt;, and &lt;code&gt;aws-cdk&lt;/code&gt;, then uses the MCP Server's API tools to provision and the &lt;code&gt;run_script&lt;/code&gt; sandbox for multi-step setup. The skills carry the wiring, so the Lambda role scopes to your specific table instead of granting access to everything (&lt;code&gt;*&lt;/code&gt;), and the CDK stack follows current patterns instead of a 2023 blog post the model half-remembers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Troubleshoot a production issue you can't reproduce
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"My checkout Lambda times out intermittently and error rates spiked this morning. Help me find why."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Point the agent at the symptom and it follows a real diagnostic path. &lt;code&gt;debugging-lambda-timeouts&lt;/code&gt; and &lt;code&gt;troubleshooting-application-failures&lt;/code&gt; give it the procedure, while &lt;code&gt;aws-observability&lt;/code&gt; and &lt;code&gt;querying-aws-cloudwatch&lt;/code&gt; let it read the actual logs and metrics through the MCP Server. It checks the configured timeout against duration metrics, looks for cold starts, and inspects downstream calls that block, then tells you what it found. You get an actual investigation rather than a guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hand an agent production access without losing sleep
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"Audit this account's S3 buckets and secrets, and flag anything risky."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the workflow that separates the toolkit from wiring up a raw MCP server. Before you run it, scope the agent's IAM role to read-only with the condition keys the MCP Server attaches, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, so it can inspect and plan but cannot change anything, even though your own role can. Writing that policy is an advanced step, and the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; explains how the condition keys fit in; you can skip it the first time through and still get value from the audit. The agent uses &lt;code&gt;securing-s3-buckets&lt;/code&gt; and &lt;code&gt;creating-secrets-using-best-practices&lt;/code&gt; as its rubric for what counts as risky, and every call lands in CloudTrail for you to review later.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to update and remove skills
&lt;/h2&gt;

&lt;p&gt;On AWS CLI &lt;code&gt;2.35.0+&lt;/code&gt;, the &lt;code&gt;aws agent-toolkit&lt;/code&gt; command group manages skills across all your agents from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws agent-toolkit list-installed-skills
aws agent-toolkit add-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-serverless
aws agent-toolkit update-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-serverless
aws agent-toolkit remove-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-cdk &lt;span class="nt"&gt;--agent&lt;/span&gt; kiro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also &lt;code&gt;search-skills&lt;/code&gt;, &lt;code&gt;list-available-skills&lt;/code&gt;, and &lt;code&gt;get-skill-metadata&lt;/code&gt; for browsing the catalog from the terminal. Without the CLI, re-run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt; to pull new skills, and remove them with &lt;code&gt;npx skills remove &amp;lt;skill-name&amp;gt;&lt;/code&gt;. The MCP Server itself is AWS-hosted, so its API coverage and docs stay current on their own. The one thing you pin and bump yourself is the proxy version in your config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is the Agent Toolkit for AWS free?&lt;/strong&gt;&lt;br&gt;
Yes. The toolkit costs nothing to install or use. You pay only standard AWS rates for the resources your agent creates or calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which AWS CLI version do I need for &lt;code&gt;aws configure agent-toolkit&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
Version 2.35.0 or later. Older versions don't recognize the command and fail with &lt;code&gt;Found invalid choice 'agent-toolkit'&lt;/code&gt;. Check yours with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I fix "Found invalid choice 'agent-toolkit'"?&lt;/strong&gt;&lt;br&gt;
Upgrade the AWS CLI to 2.35.0 or later, since the command shipped in that release. On macOS with Homebrew, run &lt;code&gt;brew upgrade awscli&lt;/code&gt;, then confirm with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need an AWS account and credentials?&lt;/strong&gt;&lt;br&gt;
Credentials are needed only for actions that touch your account, like API calls and &lt;code&gt;run_script&lt;/code&gt;. Documentation search and skill discovery work with no credentials. Anything that provisions or reads real resources needs an AWS account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which coding agents does it work with?&lt;/strong&gt;&lt;br&gt;
Kiro, Claude Code, Codex, and Cursor have first-class setups, and any MCP-compatible agent works too, including Windsurf and Cline. Plugins cover Claude Code, Codex, and Cursor; Kiro and the rest connect to the MCP server directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is it different from the AWS Labs MCP servers?&lt;/strong&gt;&lt;br&gt;
It's the successor to AWS Labs. The differences that matter: IAM condition keys that separate agent actions from human ones, CloudWatch and CloudTrail on every request, and skills evaluated end to end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I give a coding agent read-only access to AWS?&lt;/strong&gt;&lt;br&gt;
Scope its IAM role with the condition keys the MCP server attaches, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, to allow reads and deny writes. The agent can inspect and plan but not change anything, even when your own role can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I update or remove skills?&lt;/strong&gt;&lt;br&gt;
On AWS CLI 2.35.0+, use &lt;code&gt;aws agent-toolkit update-skill&lt;/code&gt; and &lt;code&gt;aws agent-toolkit remove-skill&lt;/code&gt;. Otherwise re-run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt; to update, and &lt;code&gt;npx skills remove &amp;lt;skill-name&amp;gt;&lt;/code&gt; to remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to try next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build the serverless API above, then ask the agent to add a CloudWatch alarm with &lt;code&gt;setting-up-cloudwatch-alarm-notifications&lt;/code&gt; and watch it connect the alarm to an SNS topic.&lt;/li&gt;
&lt;li&gt;Set up the read-only profile from workflow 3, hand it a real account, and confirm the agent can plan a change but not apply one. That's what makes me comfortable letting one near production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/aws/agent-toolkit-for-aws" rel="noopener noreferrer"&gt;Agent Toolkit for AWS repo&lt;/a&gt;. The source, every skill, and the plugin definitions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;What is the Agent Toolkit for AWS?&lt;/a&gt;. Components and capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/quick-start.html" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;. Install and verify.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/aws-cli.html" rel="noopener noreferrer"&gt;AWS CLI for the toolkit&lt;/a&gt;. The setup wizard and the skill commands.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/understanding-mcp-server-tools.html" rel="noopener noreferrer"&gt;AWS MCP Server tools&lt;/a&gt;. Every tool the server exposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Saurabh Dahal is a developer advocate at AWS, working with the latest agentic and AI tools for developers to help boost developer productivity. He set up the Agent Toolkit for AWS across Kiro, Codex, Claude Code, and Cursor for this guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Published June 30, 2026. Last updated June 30, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agentskills</category>
      <category>aws</category>
      <category>agents</category>
    </item>
    <item>
      <title>Setting up the Agent Toolkit for AWS in Kiro (and Codex, Claude Code, and Cursor)</title>
      <dc:creator>Saurabh "Rob" Dahal</dc:creator>
      <pubDate>Tue, 30 Jun 2026 12:30:56 +0000</pubDate>
      <link>https://dev.to/raabdahl/setting-up-the-agent-toolkit-for-aws-in-kiro-and-codex-claude-code-and-cursor-2amm</link>
      <guid>https://dev.to/raabdahl/setting-up-the-agent-toolkit-for-aws-in-kiro-and-codex-claude-code-and-cursor-2amm</guid>
      <description>&lt;p&gt;If you've let a coding agent loose on AWS, you've watched it guess. It invents API parameters that don't exist, or hands you an S3 bucket a security review will bounce on sight. The Agent Toolkit for AWS is built to stop that. By the end of this post you'll have it running in whatever editor you use, plus a tour of what's in it and three workflows worth pointing it at.&lt;/p&gt;

&lt;p&gt;I use Kiro day to day, so I'll walk through that setup first. It also works with Codex, Claude Code, Cursor, and any other agent that speaks MCP, the Model Context Protocol, which is the open standard agents use to connect to outside tools and data. I'll cover those too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Agent Toolkit for AWS?
&lt;/h2&gt;

&lt;p&gt;The Agent Toolkit for AWS is a free, AWS-supported set of tools that gives AI coding agents secure access to AWS, current documentation they can read mid-task, and tested procedures for the work they tend to fumble. It plugs into the agent you already use rather than asking you to switch. In practice, that shows up in a few ways, all detailed in the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;AWS user guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The agent stops guessing about APIs it never saw. The models behind these agents trained on data that's months or years old, so anything AWS shipped recently is missing or wrong in their heads, and the toolkit hands them current docs and references at request time. For multi-step work like least-privilege IAM or a production serverless stack, it follows a vetted skill instead of reconstructing the steps from half-memory. Every call goes through your own IAM credentials, shows up in CloudWatch, and gets logged to CloudTrail, so you can scope an agent to read-only even when your role can write. And the toolkit costs nothing on its own; you pay only for the AWS resources the agent creates.&lt;/p&gt;

&lt;p&gt;It's the successor to the MCP servers, skills, and plugins AWS shipped under &lt;a href="https://github.com/awslabs" rel="noopener noreferrer"&gt;AWS Labs&lt;/a&gt; in 2025. Two things make me reach for it over a raw MCP setup: condition keys that let a policy tell an agent apart from a human, and skills that have been evaluated end to end rather than thrown over the wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's included: the MCP server, skills, plugins, and rules files
&lt;/h2&gt;

&lt;p&gt;Four components work together (&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;reference&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The AWS MCP Server is the access layer, a single endpoint that reaches 300+ AWS services. It runs in two modes depending on what you ask for. Searching AWS docs, pulling service info, and discovering skills need no credentials at all, so the server is useful the moment you connect it. Anything that touches your account, real API calls and the sandboxed Python &lt;code&gt;run_script&lt;/code&gt; tool, runs as you through your local AWS credentials. It also stamps two condition keys on every request, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, so your policies can single out agent traffic.&lt;/p&gt;

&lt;p&gt;Skills are curated packages of instructions, scripts, and reference material for one task. The agent loads a skill only when it needs it, so they barely touch your context until they're relevant.&lt;/p&gt;

&lt;p&gt;Plugins bundle the MCP config and a curated skill set into one install. They're available for Claude Code, Codex, and Cursor; Kiro and other MCP agents connect to the server directly instead, which I cover in the setup steps below. Four ship today:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;Covers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Service selection, CDK/CloudFormation, serverless, containers, storage, observability, billing, SDK usage, deployment. &lt;strong&gt;Start here.&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-agents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Building AI agents on AWS with Amazon Bedrock and AgentCore.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-data-analytics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data lake, analytics, and ETL with S3 Tables, AWS Glue, and Athena.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws-agents-for-devsecops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Incident investigation, code review, UAT, vulnerability scanning, and pen testing with AWS DevOps Agent and AWS Security Agent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rules files are project-level config that sets guardrails: use the MCP Server, find a skill before acting, check the docs, prefer infrastructure-as-code. Rules decide how the agent behaves; skills supply what it does for a given job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which skills does the Agent Toolkit include?
&lt;/h3&gt;

&lt;p&gt;The skills are the part I underestimated at first. There are around 64 today (browse the &lt;a href="https://github.com/aws/agent-toolkit-for-aws/tree/main/skills" rel="noopener noreferrer"&gt;&lt;code&gt;skills/&lt;/code&gt; directory&lt;/a&gt; for the live list), split into core and specialized.&lt;/p&gt;

&lt;p&gt;Core skills, which ship with &lt;code&gt;aws-core&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;amazon-bedrock&lt;/code&gt;, &lt;code&gt;aws-billing-and-cost-management&lt;/code&gt;, &lt;code&gt;aws-blocks&lt;/code&gt;, &lt;code&gt;aws-cdk&lt;/code&gt;, &lt;code&gt;aws-cloudformation&lt;/code&gt;, &lt;code&gt;aws-containers&lt;/code&gt;, &lt;code&gt;aws-iam&lt;/code&gt;, &lt;code&gt;aws-messaging-and-streaming&lt;/code&gt;, &lt;code&gt;aws-observability&lt;/code&gt;, &lt;code&gt;aws-sdk-js-v3-usage&lt;/code&gt;, &lt;code&gt;aws-sdk-python-usage&lt;/code&gt;, &lt;code&gt;aws-sdk-swift-usage&lt;/code&gt;, &lt;code&gt;aws-serverless&lt;/code&gt;, &lt;code&gt;signing-in-to-aws&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Specialized skills, grouped by domain (a few from each):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless (9)&lt;/strong&gt;: &lt;code&gt;connecting-lambda-to-api-gateway&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-dynamodb&lt;/code&gt;, &lt;code&gt;debugging-lambda-timeouts&lt;/code&gt;, &lt;code&gt;processing-s3-uploads-with-step-functions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics (10)&lt;/strong&gt;: &lt;code&gt;querying-data-lake&lt;/code&gt;, &lt;code&gt;ingesting-into-data-lake&lt;/code&gt;, &lt;code&gt;managing-amazon-msk&lt;/code&gt;, &lt;code&gt;amazon-opensearch-service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database (8)&lt;/strong&gt;: &lt;code&gt;amazon-aurora-postgresql&lt;/code&gt;, &lt;code&gt;amazon-elasticache&lt;/code&gt;, &lt;code&gt;exporting-rds-to-s3&lt;/code&gt;, &lt;code&gt;rds-db2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking (5)&lt;/strong&gt;: &lt;code&gt;creating-production-vpc-multi-az&lt;/code&gt;, &lt;code&gt;routing-traffic-with-route53-and-cloudfront&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage (5)&lt;/strong&gt;: &lt;code&gt;securing-s3-buckets&lt;/code&gt;, &lt;code&gt;creating-data-lake-table&lt;/code&gt;, &lt;code&gt;storing-and-querying-vectors&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 (3)&lt;/strong&gt;, &lt;strong&gt;Operations (3)&lt;/strong&gt;, &lt;strong&gt;System table (3)&lt;/strong&gt;, &lt;strong&gt;Migration (2)&lt;/strong&gt;, &lt;strong&gt;Security and identity (1)&lt;/strong&gt;, &lt;strong&gt;Web and mobile (1)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't memorize the list. When you ask for "a Lambda behind API Gateway writing to DynamoDB," the agent pulls the matching skills on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;A handful of things need to be in place first. None take long.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An AWS account.&lt;/strong&gt; Anything that touches AWS needs one. &lt;a href="https://docs.aws.amazon.com/accounts/latest/reference/getting-started.html" rel="noopener noreferrer"&gt;Sign up here&lt;/a&gt; if you don't have one yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS credentials on your machine&lt;/strong&gt;, for the parts that act on your account. The server still connects and answers documentation and skill questions without them, but API calls and &lt;code&gt;run_script&lt;/code&gt; need them. The proxy reads the standard AWS credential chain, so &lt;code&gt;aws configure&lt;/code&gt;, an SSO login, a named profile, or the usual environment variables all work. New to this? &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html" rel="noopener noreferrer"&gt;Configuring the AWS CLI&lt;/a&gt; is the simplest path. The CLI is the common way to set credentials, not a hard requirement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt;&lt;/strong&gt;, a Python package tool that runs the MCP proxy. Install it with &lt;code&gt;brew install uv&lt;/code&gt; on macOS, or the &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;official installer&lt;/a&gt; elsewhere. The &lt;code&gt;uvx&lt;/code&gt; command in the Kiro config below comes bundled with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;, which gives you the &lt;code&gt;npx&lt;/code&gt; command used to install skills. If &lt;code&gt;npx --version&lt;/code&gt; prints nothing, install it from &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;nodejs.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CLI &lt;code&gt;2.35.0&lt;/code&gt; or later&lt;/strong&gt;, but only if you use the one-command wizard below. Check with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to set up the Agent Toolkit for AWS
&lt;/h2&gt;

&lt;p&gt;The quickest route is the AWS CLI wizard, which configures every agent you have at once. Prefer to do it by hand, or only use one editor? Skip to the per-agent steps below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up every agent at once with the AWS CLI
&lt;/h3&gt;

&lt;p&gt;On a recent AWS CLI, one command detects your installed agents, installs default skills, and configures the MCP Server for all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure agent-toolkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha worth calling out, because I hit it. On an older CLI you'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws: [ERROR]: argument subcommand: Found invalid choice 'agent-toolkit'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means your AWS CLI predates &lt;code&gt;2.35.0&lt;/code&gt;. Update it (&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;instructions&lt;/a&gt;), confirm with &lt;code&gt;aws --version&lt;/code&gt;, and rerun. Restart your agent afterward so it picks up the new MCP config.&lt;/p&gt;

&lt;p&gt;If you only use one agent, or you want to see exactly what gets wired up, the per-agent steps below do the same thing by hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kiro
&lt;/h3&gt;

&lt;p&gt;Open your Kiro MCP config and add the AWS server. Use &lt;code&gt;.kiro/settings/mcp.json&lt;/code&gt; for the current project, or &lt;code&gt;~/.kiro/settings/mcp.json&lt;/code&gt; to turn it on everywhere. Create the file if it doesn't exist yet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aws"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-proxy-for-aws@1.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://aws-mcp.us-east-1.api.aws/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--metadata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS_REGION=us-west-2"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your config already lists other servers under &lt;code&gt;mcpServers&lt;/code&gt;, add the &lt;code&gt;aws&lt;/code&gt; entry next to them instead of replacing the block, and keep the JSON valid (mind the commas). Change &lt;code&gt;AWS_REGION&lt;/code&gt; to the region you work in.&lt;/p&gt;

&lt;p&gt;Pin the proxy version rather than tracking latest. You get reproducible behavior and a guard against a bad release. Check &lt;a href="https://pypi.org/project/mcp-proxy-for-aws/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; every few weeks and bump it on purpose.&lt;/p&gt;

&lt;p&gt;Then install the skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open Kiro's MCP Server view (the Kiro panel in the sidebar, or search "MCP" in the command palette), reconnect the &lt;code&gt;aws&lt;/code&gt; server, and you're live.&lt;/p&gt;

&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;Add the marketplace, then install from inside Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex plugin marketplace add aws/agent-toolkit-for-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch Codex, run &lt;code&gt;/plugins&lt;/code&gt;, and install &lt;code&gt;aws-core&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;The plugins live on the official Anthropic marketplace, included by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin install aws-core@claude-plugins-official
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hit &lt;code&gt;Plugin not found&lt;/code&gt;? Refresh the index with &lt;code&gt;/plugin marketplace update claude-plugins-official&lt;/code&gt; and try again. Add &lt;code&gt;aws-agents&lt;/code&gt;, &lt;code&gt;aws-data-analytics&lt;/code&gt;, or &lt;code&gt;aws-agents-for-devsecops&lt;/code&gt; the same way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;Add the repo as a team marketplace: &lt;strong&gt;Settings → Plugins → Team Marketplaces → Add Marketplace → Import from Repo&lt;/strong&gt;, pointed at &lt;code&gt;aws/agent-toolkit-for-aws&lt;/code&gt;. Open the &lt;strong&gt;Plugins&lt;/strong&gt; panel and install &lt;code&gt;aws-core&lt;/code&gt; first, then the others as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other agents (Windsurf, Cline, and more)
&lt;/h3&gt;

&lt;p&gt;Anything that speaks MCP works, including Windsurf and Cline. Configure the AWS MCP Server directly (see the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html" rel="noopener noreferrer"&gt;server setup guide&lt;/a&gt;), then run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I check it's working?
&lt;/h2&gt;

&lt;p&gt;Start a fresh conversation and ask: &lt;em&gt;"What AWS Regions are available?"&lt;/em&gt; If the agent returns a list, the MCP Server is connected. For a skill check, ask it to "secure an S3 bucket" and watch it load &lt;code&gt;securing-s3-buckets&lt;/code&gt; before it writes anything. An authentication error instead means your local credentials aren't reaching the server; see Prerequisites for how to set them up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three workflows that show the payoff
&lt;/h2&gt;

&lt;p&gt;Setup is the boring part. The workflows below are where it pays off, and each one names the skills and components doing the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Stand up a serverless API, end to end
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"Build a REST API: API Gateway in front of a Lambda that reads and writes a DynamoDB table, deployed with CDK."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the kind of task agents usually botch, because it spans four services and the IAM glue between them. The agent pulls &lt;code&gt;aws-serverless&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-api-gateway&lt;/code&gt;, &lt;code&gt;connecting-lambda-to-dynamodb&lt;/code&gt;, and &lt;code&gt;aws-cdk&lt;/code&gt;, then uses the MCP Server's API tools to provision and the &lt;code&gt;run_script&lt;/code&gt; sandbox for multi-step setup. The skills carry the wiring, so the Lambda role scopes to your specific table instead of granting access to everything (&lt;code&gt;*&lt;/code&gt;), and the CDK stack follows current patterns instead of a 2023 blog post the model half-remembers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Troubleshoot a production issue you can't reproduce
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"My checkout Lambda times out intermittently and error rates spiked this morning. Help me find why."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Point the agent at the symptom and it follows a real diagnostic path. &lt;code&gt;debugging-lambda-timeouts&lt;/code&gt; and &lt;code&gt;troubleshooting-application-failures&lt;/code&gt; give it the procedure, while &lt;code&gt;aws-observability&lt;/code&gt; and &lt;code&gt;querying-aws-cloudwatch&lt;/code&gt; let it read the actual logs and metrics through the MCP Server. It checks the configured timeout against duration metrics, looks for cold starts, and inspects downstream calls that block, then tells you what it found. You get an actual investigation rather than a guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hand an agent production access without losing sleep
&lt;/h3&gt;

&lt;p&gt;Prompt: &lt;em&gt;"Audit this account's S3 buckets and secrets, and flag anything risky."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the workflow that separates the toolkit from wiring up a raw MCP server. Before you run it, scope the agent's IAM role to read-only with the condition keys the MCP Server attaches, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, so it can inspect and plan but cannot change anything, even though your own role can. Writing that policy is an advanced step, and the &lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; explains how the condition keys fit in; you can skip it the first time through and still get value from the audit. The agent uses &lt;code&gt;securing-s3-buckets&lt;/code&gt; and &lt;code&gt;creating-secrets-using-best-practices&lt;/code&gt; as its rubric for what counts as risky, and every call lands in CloudTrail for you to review later.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to update and remove skills
&lt;/h2&gt;

&lt;p&gt;On AWS CLI &lt;code&gt;2.35.0+&lt;/code&gt;, the &lt;code&gt;aws agent-toolkit&lt;/code&gt; command group manages skills across all your agents from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws agent-toolkit list-installed-skills
aws agent-toolkit add-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-serverless
aws agent-toolkit update-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-serverless
aws agent-toolkit remove-skill &lt;span class="nt"&gt;--skill-name&lt;/span&gt; aws-cdk &lt;span class="nt"&gt;--agent&lt;/span&gt; kiro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also &lt;code&gt;search-skills&lt;/code&gt;, &lt;code&gt;list-available-skills&lt;/code&gt;, and &lt;code&gt;get-skill-metadata&lt;/code&gt; for browsing the catalog from the terminal. Without the CLI, re-run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt; to pull new skills, and remove them with &lt;code&gt;npx skills remove &amp;lt;skill-name&amp;gt;&lt;/code&gt;. The MCP Server itself is AWS-hosted, so its API coverage and docs stay current on their own. The one thing you pin and bump yourself is the proxy version in your config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is the Agent Toolkit for AWS free?&lt;/strong&gt;&lt;br&gt;
Yes. The toolkit costs nothing to install or use. You pay only standard AWS rates for the resources your agent creates or calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which AWS CLI version do I need for &lt;code&gt;aws configure agent-toolkit&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
Version 2.35.0 or later. Older versions don't recognize the command and fail with &lt;code&gt;Found invalid choice 'agent-toolkit'&lt;/code&gt;. Check yours with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I fix "Found invalid choice 'agent-toolkit'"?&lt;/strong&gt;&lt;br&gt;
Upgrade the AWS CLI to 2.35.0 or later, since the command shipped in that release. On macOS with Homebrew, run &lt;code&gt;brew upgrade awscli&lt;/code&gt;, then confirm with &lt;code&gt;aws --version&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need an AWS account and credentials?&lt;/strong&gt;&lt;br&gt;
Credentials are needed only for actions that touch your account, like API calls and &lt;code&gt;run_script&lt;/code&gt;. Documentation search and skill discovery work with no credentials. Anything that provisions or reads real resources needs an AWS account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which coding agents does it work with?&lt;/strong&gt;&lt;br&gt;
Kiro, Claude Code, Codex, and Cursor have first-class setups, and any MCP-compatible agent works too, including Windsurf and Cline. Plugins cover Claude Code, Codex, and Cursor; Kiro and the rest connect to the MCP server directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is it different from the AWS Labs MCP servers?&lt;/strong&gt;&lt;br&gt;
It's the successor to AWS Labs. The differences that matter: IAM condition keys that separate agent actions from human ones, CloudWatch and CloudTrail on every request, and skills evaluated end to end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I give a coding agent read-only access to AWS?&lt;/strong&gt;&lt;br&gt;
Scope its IAM role with the condition keys the MCP server attaches, &lt;code&gt;aws:ViaAWSMCPService&lt;/code&gt; and &lt;code&gt;aws:CalledViaAWSMCP&lt;/code&gt;, to allow reads and deny writes. The agent can inspect and plan but not change anything, even when your own role can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I update or remove skills?&lt;/strong&gt;&lt;br&gt;
On AWS CLI 2.35.0+, use &lt;code&gt;aws agent-toolkit update-skill&lt;/code&gt; and &lt;code&gt;aws agent-toolkit remove-skill&lt;/code&gt;. Otherwise re-run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt; to update, and &lt;code&gt;npx skills remove &amp;lt;skill-name&amp;gt;&lt;/code&gt; to remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to try next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build the serverless API above, then ask the agent to add a CloudWatch alarm with &lt;code&gt;setting-up-cloudwatch-alarm-notifications&lt;/code&gt; and watch it connect the alarm to an SNS topic.&lt;/li&gt;
&lt;li&gt;Set up the read-only profile from workflow 3, hand it a real account, and confirm the agent can plan a change but not apply one. That's what makes me comfortable letting one near production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/aws/agent-toolkit-for-aws" rel="noopener noreferrer"&gt;Agent Toolkit for AWS repo&lt;/a&gt;. The source, every skill, and the plugin definitions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/what-is-agent-toolkit.html" rel="noopener noreferrer"&gt;What is the Agent Toolkit for AWS?&lt;/a&gt;. Components and capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/quick-start.html" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;. Install and verify.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/aws-cli.html" rel="noopener noreferrer"&gt;AWS CLI for the toolkit&lt;/a&gt;. The setup wizard and the skill commands.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/understanding-mcp-server-tools.html" rel="noopener noreferrer"&gt;AWS MCP Server tools&lt;/a&gt;. Every tool the server exposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Saurabh Dahal is a developer advocate at AWS, working with the latest agentic and AI tools for developers to help boost developer productivity. He set up the Agent Toolkit for AWS across Kiro, Codex, Claude Code, and Cursor for this guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Published June 30, 2026. Last updated June 30, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agentskills</category>
      <category>aws</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Let My AI Agent Build a Bedrock RAG Knowledge Base, Here Are the 2 Mistakes the AWS Agent Toolkit Caught</title>
      <dc:creator>Saurabh "Rob" Dahal</dc:creator>
      <pubDate>Thu, 25 Jun 2026 18:29:01 +0000</pubDate>
      <link>https://dev.to/raabdahl/i-let-my-ai-agent-build-a-bedrock-rag-knowledge-base-here-are-the-2-mistakes-the-aws-agent-toolkit-3l49</link>
      <guid>https://dev.to/raabdahl/i-let-my-ai-agent-build-a-bedrock-rag-knowledge-base-here-are-the-2-mistakes-the-aws-agent-toolkit-3l49</guid>
      <description>&lt;p&gt;&lt;em&gt;Provisioning a Bedrock RAG knowledge base with S3 Vectors, without the hallucinated API calls.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've asked an AI coding agent to set up AWS, you've seen it confidently invent a parameter, reach for a deprecated service, or burn ten minutes retrying against a service it never saw in training. The failure mode that bites hardest is the silent one: the agent &lt;em&gt;thinks&lt;/em&gt; it succeeded, and you find out an hour later.&lt;/p&gt;

&lt;p&gt;I hit two of these while standing up the retrieval layer for a LangGraph support bot, an Amazon Bedrock Knowledge Base backed by Amazon S3 Vectors. I'd love to say I caught both with deep AWS expertise. I caught them because the &lt;a href="https://github.com/aws/agent-toolkit-for-aws" rel="noopener noreferrer"&gt;Agent Toolkit for AWS&lt;/a&gt; read the docs I hadn't. Both would have shipped, and neither did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second setup
&lt;/h2&gt;

&lt;p&gt;The goal: take a folder of markdown product docs and make them queryable by meaning, so an agent can answer "is this safe for color-treated hair?" from the real docs instead of guessing. Think of it as giving the agent a library it can search instead of making things up. That's the &lt;em&gt;retrieval&lt;/em&gt; half of RAG, the foundation a LangGraph agent will later call as a tool.&lt;/p&gt;

&lt;p&gt;Four moving parts, wrapped in one managed service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source bucket&lt;/strong&gt;: an S3 bucket holding the docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embeddings&lt;/strong&gt;: Amazon Titan Text Embeddings V2 (1024-dim vectors).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector store&lt;/strong&gt;: Amazon S3 Vectors. I chose it over OpenSearch Serverless because it has no always-on compute, the difference between cents and a monthly surprise for a demo that sits idle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base&lt;/strong&gt;: Amazon Bedrock Knowledge Bases ties it together into one thing you can query with a &lt;code&gt;retrieve&lt;/code&gt; call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To follow along, you need an AWS account, a non-root IAM identity with credentials configured locally, &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; installed, and the toolkit installed in your agent. The fastest path across Kiro, Claude Code, Cursor, and Codex is the AWS CLI installer, &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/aws-cli-agent-toolkit/" rel="noopener noreferrer"&gt;&lt;code&gt;aws configure agent-toolkit&lt;/code&gt;&lt;/a&gt;; in Kiro you can instead add the &lt;a href="https://aws.amazon.com/blogs/aws/the-aws-mcp-server-is-now-generally-available/" rel="noopener noreferrer"&gt;AWS MCP Server&lt;/a&gt; to &lt;code&gt;.kiro/settings/mcp.json&lt;/code&gt; (pin the &lt;a href="https://pypi.org/project/mcp-proxy-for-aws/" rel="noopener noreferrer"&gt;&lt;code&gt;mcp-proxy-for-aws&lt;/code&gt;&lt;/a&gt; version) and run &lt;code&gt;npx skills add aws/agent-toolkit-for-aws/skills&lt;/code&gt;. The toolkit plugs into the agent you already use and loads task-specific &lt;em&gt;skills&lt;/em&gt; on demand; I used the &lt;code&gt;amazon-bedrock&lt;/code&gt; skill, which carries the validated, current procedure for building a Knowledge Base. That word, "current," is the whole story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotcha #1: the model id was already dead
&lt;/h2&gt;

&lt;p&gt;My first instinct, straight from an older tutorial, was &lt;code&gt;anthropic.claude-3-5-sonnet-20240620-v1:0&lt;/code&gt;. Calling it returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ResourceNotFoundException: This model version has reached the end of its life.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix the toolkit's doc search surfaced: current Anthropic models on Bedrock are &lt;strong&gt;inference-profile only&lt;/strong&gt;. You invoke them through a cross-region profile id like &lt;code&gt;us.anthropic.claude-sonnet-4-5-20250929-v1:0&lt;/code&gt;, not the bare on-demand id.&lt;/p&gt;

&lt;p&gt;On its own, an agent might not even diagnose this correctly. "Not found" reads like a permissions or region problem, so it could swap in another stale id and hit "on-demand throughput isn't supported" instead, flailing sideways. The toolkit got it right because it read the current model docs, not because it happened to remember them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotcha #2: Bedrock won't create the S3 Vectors index for you
&lt;/h2&gt;

&lt;p&gt;I created the vector bucket, pointed the Knowledge Base at an index name, and assumed Bedrock would create the index. It didn't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ValidationException: The specified index could not be found (S3Vectors 404)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real requirement, from the S3 Vectors docs: you create the index yourself, and it must declare two &lt;strong&gt;non-filterable metadata keys&lt;/strong&gt; that Bedrock uses to store chunk text and metadata. Miss them and ingestion fails later with a cryptic error far from the cause. The working command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3vectors create-index &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--vector-bucket-name&lt;/span&gt; &amp;lt;VECTOR_BUCKET&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--index-name&lt;/span&gt; &amp;lt;INDEX_NAME&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; float32 &lt;span class="nt"&gt;--dimension&lt;/span&gt; 1024 &lt;span class="nt"&gt;--distance-metric&lt;/span&gt; cosine &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--metadata-configuration&lt;/span&gt; &lt;span class="s1"&gt;'{"nonFilterableMetadataKeys":["AMAZON_BEDROCK_TEXT","AMAZON_BEDROCK_METADATA"]}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the one that best captures why current docs matter. S3 Vectors launched in 2025, so the requirement isn't in most models' training data. A toolkit-less agent would most likely create the index, &lt;em&gt;think it succeeded&lt;/em&gt;, and only hit the wall at ingestion time, then burn an afternoon recreating it with the wrong config. The dimension (1024) and distance metric here aren't arbitrary either: they have to match the Titan embedding model, which is the kind of cross-resource constraint an agent gets wrong when it's guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest fell into place, and it works
&lt;/h2&gt;

&lt;p&gt;With those two out of the way, the validated sequence ran clean: create the IAM service role (trust &lt;code&gt;bedrock.amazonaws.com&lt;/code&gt; with confused-deputy conditions, so another customer can't trick the role into acting on their resources, plus least-privilege permissions to invoke Titan, read the bucket, and use the vector index), create the Knowledge Base, attach the S3 data source with fixed-size chunking (300 tokens, 20% overlap), and run ingestion. Result: 10/10 documents indexed, zero failures.&lt;/p&gt;

&lt;p&gt;The proof is a retrieval query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock-agent-runtime retrieve &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--knowledge-base-id&lt;/span&gt; &amp;lt;KB_ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--retrieval-query&lt;/span&gt; &lt;span class="s1"&gt;'{"text":"Is the Curl Cream safe for color-treated hair?"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Top hit came back at &lt;strong&gt;0.86 similarity&lt;/strong&gt;, on the exact product doc with the right answer. The library is stocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it bought me, and what I'd do differently
&lt;/h2&gt;

&lt;p&gt;Strip away the demo and the toolkit changed two things: it handed the agent the validated setup &lt;em&gt;order&lt;/em&gt; up front (no trial-and-error), and it caught two mistakes a model trained months ago wouldn't know, because it checks current docs and ships procedures AWS maintains. AWS reports developers see fewer iterations and errors with it; on this build, the two catches alone saved me an afternoon.&lt;/p&gt;

&lt;p&gt;Two honest gaps. First, the toolkit's own rules recommend infrastructure-as-code over direct CLI, and I didn't follow that. I ran CLI calls and tracked them in a tagged manifest for teardown. It works, but CDK or CloudFormation would be the reproducible artifact a reader could clone. Second, I left the IAM role's trust policy scoped to &lt;code&gt;knowledge-base/*&lt;/code&gt; instead of the specific KB id; tightening that &lt;code&gt;aws:SourceArn&lt;/code&gt; is the obvious hardening step before this is anything but a demo.&lt;/p&gt;

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

&lt;p&gt;This is the retrieval foundation, not the whole app. Two concrete next steps, and you could take either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Close the loop.&lt;/strong&gt; Wire a LangGraph agent to call this Knowledge Base as a tool, so it retrieves &lt;em&gt;and&lt;/em&gt; generates grounded answers. That's when "RAG knowledge base" graduates to "RAG application."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it reproducible.&lt;/strong&gt; Convert the ad-hoc CLI provisioning into CDK or CloudFormation, so the whole stack stands up and tears down with one command, the way the toolkit's own rules recommend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you take one thing: the toolkit's real value isn't typing commands for you, it's making better decisions, grounded in current docs, on the things an AI agent gets wrong in ways you don't notice until an hour later.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>agentskills</category>
      <category>bedrock</category>
    </item>
  </channel>
</rss>
