<?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: jamongx</title>
    <description>The latest articles on DEV Community by jamongx (@jamongx).</description>
    <link>https://dev.to/jamongx</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%2F474134%2F099df63d-3950-4ba0-ad3d-208b244c3b37.jpeg</url>
      <title>DEV Community: jamongx</title>
      <link>https://dev.to/jamongx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jamongx"/>
    <language>en</language>
    <item>
      <title>The Four Layers of AI Engineering: From Prompts to Loops</title>
      <dc:creator>jamongx</dc:creator>
      <pubDate>Mon, 21 Sep 2026 14:12:17 +0000</pubDate>
      <link>https://dev.to/jamongx/the-four-layers-of-ai-engineering-from-prompts-to-loops-2997</link>
      <guid>https://dev.to/jamongx/the-four-layers-of-ai-engineering-from-prompts-to-loops-2997</guid>
      <description>&lt;p&gt;"Prompt engineering" has been a buzzword for a few years now. But if you look at what actually happens in practice, the prompt is only the innermost piece of the picture. I find it useful to think of AI engineering as four layers: prompt, context, harness, and loop. You start with the prompt at the center, and as you move outward, you deal with the information the model sees, then the code around the model, then the structure that keeps it running.&lt;/p&gt;

&lt;p&gt;To be clear, this isn't an official industry taxonomy. The boundaries between layers overlap in places. But as a practical frame for deciding what to improve next in an AI system, it works well.&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%2Flpwmxnkzc7zcfdy6wi5w.webp" 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%2Flpwmxnkzc7zcfdy6wi5w.webp" alt="Four layers of AI engineering: prompt at the center, then context, harness, and loop moving outward" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Definitions alone would be too abstract, so let's use the same scenario across all four layers: &lt;strong&gt;a system where an AI reviews the code every time a PR is opened.&lt;/strong&gt; Watching the same goal change shape at each layer makes the role of each one clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;The innermost layer. This is what you type directly into the chat box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what to ask&lt;/li&gt;
&lt;li&gt;how to ask it&lt;/li&gt;
&lt;li&gt;what to tell the model to avoid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example.&lt;/strong&gt; In the code review scenario, this is the stage where you paste a diff into a chat window and ask for a review.&lt;/p&gt;

&lt;p&gt;A bad prompt:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;A better prompt:&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="p"&gt;Review this diff.
&lt;/span&gt;&lt;span class="gd"&gt;- Check for potential bugs, then security issues, then performance, in that order.
- Skip style nitpicks. The linter handles those.
- If there's nothing wrong, just say "no issues". Don't invent problems to have something to say.
- For each finding, include the line number and a suggested fix.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same model, same diff, but the focus and consistency of the output change quite a bit, because you've spelled out what to look at, what to ignore, and what shape the answer should take. The "don't invent problems" line matters more than it looks. Without it, the model sometimes flags trivial style issues or manufactures findings just to produce something.&lt;/p&gt;

&lt;p&gt;This is also the layer where most people stay when they first use AI. The problem is that no matter how much you polish the prompt, if the model doesn't know your project, the output stays generic. Even with the prompt above, the model has no idea what error handling convention your team uses or where this function gets called from.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Context Engineering
&lt;/h2&gt;

&lt;p&gt;Everything you provide beyond the direct request, so the model has something to base its judgment on. This is the second layer, wrapped around the prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;system instructions&lt;/li&gt;
&lt;li&gt;reference documents&lt;/li&gt;
&lt;li&gt;conversation history&lt;/li&gt;
&lt;li&gt;good examples (few-shot)&lt;/li&gt;
&lt;li&gt;expected output samples and writing rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example.&lt;/strong&gt; In the code review scenario, context engineering means laying out the background the model needs instead of just throwing a diff at it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[System instructions]
You are a senior reviewer on our team. Review against the conventions below.

[Reference: team conventions]
- Errors are returned as Result types, not thrown as exceptions.
- All DB access goes through the repository layer.
- External API calls must specify a timeout.

[Reference: related code]
- The relevant parts of the 3 files that call this function

[Good examples: 2 past review comments]
- The tone and depth of reviews our team actually writes

[Prompt]
Review this diff. (same as before)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the model judges the code against "our team's standards" rather than "generally good code." If someone throws an exception in a place where the team convention calls for a Result type, the model can flag that violation. That's a finding you'd rarely get without context.&lt;/p&gt;

&lt;p&gt;CLAUDE.md in Claude Code is the classic example of this layer. Put your project structure, coding conventions, and build commands in there once, and you don't have to explain them in every prompt. You can also split rules by file type or directory with &lt;code&gt;.claude/rules/&lt;/code&gt;, and provide documents like a DESIGN.md that captures design intent as context when it's needed. These files are persistent context: write them once, and they keep getting used. An implementation plan you write for a specific task, on the other hand, is closer to one-off context. If you keep the plan and its progress updated as you go, it helps the model keep track of the overall direction and where it currently is. Retrieving relevant documents with RAG and feeding them to the model is another typical form of context engineering. MCP is related to context in that it brings outside information to the model, but the part where you connect tools and manage calls belongs to the next layer, the harness. It's one of the clearest places where the boundaries blur.&lt;/p&gt;

&lt;p&gt;So if a task depends on project-specific rules or related code, polishing the prompt only gets you so far. The model has never seen your codebase, and if you don't give it the information it needs, it has no choice but to fill the gaps with inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Harness Engineering
&lt;/h2&gt;

&lt;p&gt;The harness is the code around the model call. Note that it wraps the call itself, not the model's output: assemble the prompt and context, call the model, validate what comes back, retry on failure. It's the software structure around that one cycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tool connections (tool calling, MCP servers)&lt;/li&gt;
&lt;li&gt;output validation&lt;/li&gt;
&lt;li&gt;retry logic&lt;/li&gt;
&lt;li&gt;structured output (JSON schema)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the first two layers are about designing the input you hand to the model (not just what to instruct, but which documents to pull in and what to leave out), the harness is the code that processes that input reliably in a real system. It's traditional software engineering: validation, retries, exception handling. A familiar analogy is an external API client. It's a lot like putting timeouts, retries, and response validation around a remote service. The difference is that model calls add a new failure class on top of network errors and 5xx responses: semantic failures, where the output is malformed or plausibly wrong.&lt;/p&gt;

&lt;p&gt;Model output is probabilistic, so you get format errors and missing pieces. You ask for JSON and it comes back wrapped in a markdown code block, or with a field missing. The harness validates and retries on these failures, and it also manages tool calls and feeds their results back in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example.&lt;/strong&gt; To run the code review in GitHub Actions instead of a chat window, you need code around the model call. What follows is pseudocode for illustration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pseudocode for illustration. In practice, use a Pydantic model or JSON Schema.
&lt;/span&gt;&lt;span class="n"&gt;REVIEW_SCHEMA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;review_pr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;retry_feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;# never mutate the original diff
&lt;/span&gt;            &lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;# failure records passed in by the outer loop
&lt;/span&gt;            &lt;span class="n"&gt;retry_feedback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;retry_feedback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# retry reasons travel on a separate channel
&lt;/span&gt;            &lt;span class="n"&gt;output_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REVIEW_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;REVIEW_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;retry_feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Schema error in previous response: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="c1"&gt;# cross-check that each file and line number belongs to an actual changed hunk
&lt;/span&gt;        &lt;span class="n"&gt;invalid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_invalid_comments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;invalid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;retry_feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Some comments don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t match actual diff lines.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ReviewFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed after 3 retries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The harness does three things here. It requests structured output and validates it against a schema, it retries with the failure reason fed back in, and it cross-checks locations the model may have made up (files or lines that aren't in any changed hunk). That last one matters most. Prompts alone can't fully prevent bad output, so anything you can verify in code, verify in code. Retrying or failing on invalid comments, rather than silently filtering them out, is also a deliberate choice. If you just drop the made-up comments, a response where every comment is invalid becomes an empty list, which reads as "no issues found."&lt;/p&gt;

&lt;p&gt;This validation and recovery logic is what turns a model call into a reliable software component. Things that work fine in a demo fail intermittently in production, on parsing or validation, and catching those failures is the harness's job. A production harness also includes logging, cost tracking, and collecting failure cases. If you don't record failures, you don't know what to improve.&lt;/p&gt;

&lt;p&gt;By this post's classification, Claude Code itself can be seen as a harness around the model. It provides the execution structure: not just model calls, but tool execution, file editing, and permission checks. If you use Claude Code, you're already using a harness every day.&lt;/p&gt;

&lt;p&gt;The difference between context and harness shows up clearly if you compare CLAUDE.md with hooks. Write "run the linter before committing" in CLAUDE.md and it's context. It nudges the model to comply, but nothing guarantees it happens. Configure a &lt;code&gt;PreToolUse&lt;/code&gt; command hook that fires before &lt;code&gt;git commit&lt;/code&gt; runs, and now the commit can be blocked in code when the lint fails. Same goal, different enforcement depending on which layer it lives in. Things you can leave to the model's judgment go in context; things that must be guaranteed go in the harness.&lt;/p&gt;

&lt;p&gt;But if retries are the harness's job, what's different about the next layer, the loop? The unit of retry. The &lt;code&gt;for attempt in range(3)&lt;/code&gt; in the code above retries the same model call until it gets output in the right shape. The goal is one valid response. A loop, on the other hand, repeats the entire review-fix-test cycle until it reaches a target state. The harness builds reliable parts; the loop assembles those parts and drives them toward a goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Loop Engineering
&lt;/h2&gt;

&lt;p&gt;The outermost layer. This is where the system starts running on its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a goal and stop conditions&lt;/li&gt;
&lt;li&gt;iterating with self-checks and adjustments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even a system with a solid harness stops after one run, which means a human has to keep issuing the next instruction. A loop sets a goal and stop conditions, like "until all tests pass" or "until lint errors hit zero," and lets the system drive itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example.&lt;/strong&gt; Let's push the review system one step further: instead of just pointing out problems, it fixes them too, repeating review, fix, and re-verify on its own. Pseudocode again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MAX_ITERATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;auto_fix_pr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;                                   &lt;span class="c1"&gt;# loop state that persists across iterations
&lt;/span&gt;
    &lt;span class="c1"&gt;# check the baseline first: tests that were already broken go to a human
&lt;/span&gt;    &lt;span class="n"&gt;baseline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request_human_review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tests were failing before auto-fix started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;review_pr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# reusing layer 3
&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# mark the AI review as passed; final approval stays with a human
&lt;/span&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request_human_approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Passed AI review and tests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# no comments but tests fail: skip fixing, go to the next iteration
&lt;/span&gt;            &lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failure_log&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fix_commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply_fixes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# keep the fix commit ID
&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                      &lt;span class="c1"&gt;# self-check
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;                           &lt;span class="c1"&gt;# clear resolved failure records
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;pr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;revert_commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fix_commit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# revert exactly the commit the AI made
&lt;/span&gt;            &lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;                       &lt;span class="c1"&gt;# carry the failure log to the next iteration
&lt;/span&gt;                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failure_log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request_human_review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unresolved after 5 iterations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# stop condition
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is in there: a goal (no comments plus passing tests), self-checks (running tests), adjustment (revert on failure and carry the log forward in &lt;code&gt;feedback&lt;/code&gt;), and stop conditions (5 iterations max, then escalate to a human). The fact that &lt;code&gt;auto_fix_pr&lt;/code&gt; calls &lt;code&gt;review_pr&lt;/code&gt; from layer 3 directly is the relationship from the previous section: the loop assembles the parts the harness built.&lt;/p&gt;

&lt;p&gt;Failure logs go into &lt;code&gt;feedback&lt;/code&gt; outside the loop body, not into a local variable of the current iteration. That's what lets the next model call actually see the earlier failures. And once a fix passes the tests, the accumulated failure records get cleared. There's no reason for the next review to keep referring to errors that were already resolved.&lt;/p&gt;

&lt;p&gt;Fix commits are only created when there are comments, and the revert targets the exact commit ID that &lt;code&gt;apply_fixes&lt;/code&gt; returned. Reverting "the last commit" can delete the wrong commit if a human pushes while the loop is running.&lt;/p&gt;

&lt;p&gt;Checking the baseline tests before entering the loop follows the same logic. To treat a test failure as the result of an AI fix, you first have to know the PR's tests were passing before the auto-fix started. If they were already failing, reverting the last fix commit won't solve anything.&lt;/p&gt;

&lt;p&gt;It also matters that meeting the conditions doesn't auto-approve the PR. The AI finding no comments is not a guarantee the code is fine, so final merge approval stays with a human. Permission control spans both the harness and the loop, but it becomes especially important at the loop stage, once the system starts acting repeatedly. In real operations, it's safer to auto-fix only low-risk categories like formatting rather than applying every comment automatically.&lt;/p&gt;

&lt;p&gt;Claude Code fixing code, running tests, reading the failures, and fixing again is a good example of a loop.&lt;/p&gt;

&lt;p&gt;The heart of it is the &lt;a href="https://dev.to/claude-code-agent-loops/"&gt;stop conditions&lt;/a&gt;. Without a max iteration count, a cost ceiling, and a success criterion, a loop either runs away or spins in place. Take &lt;code&gt;MAX_ITERATIONS&lt;/code&gt; and the human escalation out of the example above, and you have a system that burns tokens forever on a PR whose tests can never be fixed.&lt;/p&gt;

&lt;p&gt;Without a loop, a human has to check the result and issue the next instruction on every iteration. Iteration with self-checks is a core ingredient of agent systems. But an actual agent combines this with tool use, state management, and permission control, so a loop by itself is not the whole of an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;In the code review scenario&lt;/th&gt;
&lt;th&gt;Without it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Prompt&lt;/td&gt;
&lt;td&gt;The request you type&lt;/td&gt;
&lt;td&gt;"What to look at, what to ignore"&lt;/td&gt;
&lt;td&gt;Nothing starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Context&lt;/td&gt;
&lt;td&gt;Background the model sees&lt;/td&gt;
&lt;td&gt;Team conventions, related code, past reviews&lt;/td&gt;
&lt;td&gt;It guesses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Harness&lt;/td&gt;
&lt;td&gt;Validation, retries, tool wiring&lt;/td&gt;
&lt;td&gt;Schema validation, line-number cross-checks&lt;/td&gt;
&lt;td&gt;It wobbles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Loop&lt;/td&gt;
&lt;td&gt;Goals, stop conditions, iteration&lt;/td&gt;
&lt;td&gt;Review-fix-test cycle, human keeps final approval&lt;/td&gt;
&lt;td&gt;It stalls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A great prompt without context guesses. Great context without a harness wobbles. A harness without a loop stalls. And for repetitive work without a loop, you become the bottleneck.&lt;/p&gt;

&lt;p&gt;If all you've been doing is polishing prompts, you've been working on just the innermost layer. When the results still disappoint, the next improvement may be further out.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://jamongx.com/four-layers-of-ai-engineering/" rel="noopener noreferrer"&gt;jamongx.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Claude Code Skills Guide: How to Automate Your Development Workflow</title>
      <dc:creator>jamongx</dc:creator>
      <pubDate>Mon, 13 Jul 2026 01:14:05 +0000</pubDate>
      <link>https://dev.to/jamongx/claude-code-skills-guide-how-to-automate-your-development-workflow-39ni</link>
      <guid>https://dev.to/jamongx/claude-code-skills-guide-how-to-automate-your-development-workflow-39ni</guid>
      <description>&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; is a terminal-based coding agent that can automate the repetitive parts of your development workflow, not just generate code.&lt;/p&gt;

&lt;p&gt;This article isn't about installation or basic usage. It's written for developers already using Claude Code who want to learn &lt;strong&gt;how to design Skills that deliver meaningful automation and consistency in real-world projects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Among Claude Code's features, &lt;strong&gt;Skills&lt;/strong&gt; are the main way to define how Claude should handle repeatable tasks and follow your project's engineering conventions. In this article, we'll look at how they keep code quality consistent across a team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Updated July 2026&lt;/strong&gt; — The January version of this guide described Skills as single &lt;code&gt;.md&lt;/code&gt; files in &lt;code&gt;.claude/commands/&lt;/code&gt;. Skills have since become directory-based (&lt;code&gt;.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;), adopted a formal frontmatter specification, and become an open standard at &lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;agentskills.io&lt;/a&gt;. This revision reflects the current format. The examples come from skills I actually use in real projects.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. What Are Skills?
&lt;/h2&gt;

&lt;p&gt;In Claude Code, a &lt;strong&gt;Skill&lt;/strong&gt; is a directory containing a &lt;code&gt;SKILL.md&lt;/code&gt; file with the instructions, resources, and execution steps Claude follows when the skill is invoked. For personal and project skills, the directory name becomes the command name: &lt;code&gt;.claude/skills/code-review/SKILL.md&lt;/code&gt; gives you &lt;code&gt;/code-review&lt;/code&gt;. (Plugin skills are namespaced by the plugin name: &lt;code&gt;/my-plugin:review&lt;/code&gt;.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Rules are your 'Policy Documents'&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Skills are your 'Standard Operating Procedures'&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important distinction is this: &lt;strong&gt;a Skill is not an independent agent.&lt;/strong&gt; It packages instructions, resources, and tool permissions—Claude, or you, decides when to invoke it, unless the frontmatter restricts invocation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you remember "custom slash commands"&lt;/strong&gt; (&lt;code&gt;.claude/commands/*.md&lt;/code&gt;): they've been merged into Skills. A file at &lt;code&gt;.claude/commands/deploy.md&lt;/code&gt; and a skill at &lt;code&gt;.claude/skills/deploy/SKILL.md&lt;/code&gt; both create &lt;code&gt;/deploy&lt;/code&gt;, and old command files keep working. Skills are the recommended format—they add supporting files, invocation control, and a richer frontmatter. If both define the same name, the skill wins.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Skill File Structure and Location
&lt;/h2&gt;

&lt;p&gt;Skills can be managed per-project or globally across your machine:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Personal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All your projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Project&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This project only (shared via Git)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;plugin&amp;gt;/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wherever the plugin is enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The file must be named exactly &lt;code&gt;SKILL.md&lt;/code&gt;, and a skill is a &lt;em&gt;directory&lt;/em&gt;, not a single file. That directory can carry supporting material that loads only when needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code-review/
├── SKILL.md          # required: frontmatter + instructions
├── references/       # detailed docs, loaded on demand
├── scripts/          # executable helpers (run, not loaded)
└── assets/           # templates, static resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For me, this is the most useful improvement over the old single-file format. Keep &lt;code&gt;SKILL.md&lt;/code&gt; under ~500 lines and push heavy reference material into &lt;code&gt;references/&lt;/code&gt;—the body stays in context for the whole session once loaded, so every line has a recurring token cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key: YAML Frontmatter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-review&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Review code against .claude/rules/ for architecture and convention violations.&lt;/span&gt;
&lt;span class="na"&gt;argument-hint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[path]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[--staged|--branch]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[--fix]"&lt;/span&gt;
&lt;span class="na"&gt;allowed-tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read Glob Grep Bash(git *)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ The &lt;code&gt;description&lt;/code&gt; field is still &lt;strong&gt;critical&lt;/strong&gt;. Claude normally sees the names and descriptions of available Skills and uses that metadata to decide which one is relevant. If you say "review my code," that request gets matched against skill descriptions—so yours must contain &lt;strong&gt;clear, searchable keywords&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One distinction worth knowing before the table: the Agent Skills standard defines the portable core fields (&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;license&lt;/code&gt;, &lt;code&gt;compatibility&lt;/code&gt;, &lt;code&gt;metadata&lt;/code&gt;, &lt;code&gt;allowed-tools&lt;/code&gt;). The rest below—&lt;code&gt;argument-hint&lt;/code&gt;, &lt;code&gt;disable-model-invocation&lt;/code&gt;, &lt;code&gt;user-invocable&lt;/code&gt;, &lt;code&gt;context&lt;/code&gt;—are &lt;strong&gt;Claude Code extensions&lt;/strong&gt;. The table covers the fields used in this guide, not every option Claude Code supports (there are also &lt;code&gt;when_to_use&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;paths&lt;/code&gt;, &lt;code&gt;hooks&lt;/code&gt;, and more):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Display name (defaults to the directory name)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-invocation trigger. Keep it ≤1,024 chars for cross-tool compatibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;argument-hint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Autocomplete hint shown after &lt;code&gt;/name&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;allowed-tools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tools Claude may use &lt;strong&gt;without permission prompts&lt;/strong&gt; while the skill runs (space-separated per the standard; Claude Code also accepts commas)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable-model-invocation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;true&lt;/code&gt; = only you can trigger it; Claude never auto-invokes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user-invocable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;false&lt;/code&gt; = hidden from the &lt;code&gt;/&lt;/code&gt; menu; Claude-only background knowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context: fork&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the skill in an isolated subagent context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of these encode a design decision the old format couldn't express: &lt;strong&gt;who is allowed to pull the trigger.&lt;/strong&gt; For side-effect workflows—deploying, committing, sending messages—set &lt;code&gt;disable-model-invocation: true&lt;/code&gt; so Claude can't decide on its own that now is a good time to deploy. For pure background knowledge, set &lt;code&gt;user-invocable: false&lt;/code&gt; so it stays out of your command menu.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Real Example: &lt;code&gt;/code-review&lt;/code&gt; Skill
&lt;/h2&gt;

&lt;p&gt;The architecture-review skill from the January version of this post is still the one I use every day—it has just grown up. Here's the frontmatter of my current production &lt;code&gt;/code-review&lt;/code&gt; skill:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-review&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Review code against .claude/rules/ for architecture and convention&lt;/span&gt;
  &lt;span class="s"&gt;violations. Supports --staged, --head, --last, --today, --branch scope options.&lt;/span&gt;
  &lt;span class="s"&gt;Add --fix to auto-correct.&lt;/span&gt;
&lt;span class="na"&gt;argument-hint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[path]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[--staged|--head|--last|--today|--branch]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[--fix]"&lt;/span&gt;
&lt;span class="na"&gt;allowed-tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Glob, Grep, Edit, Bash(git *), Bash(find *)&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current version relies on two features that didn't exist in January:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Arguments.&lt;/strong&gt; &lt;code&gt;$ARGUMENTS&lt;/code&gt; in the skill body is substituted with whatever you type after the command, so one skill covers many scopes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Invocation&lt;/th&gt;
&lt;th&gt;Review scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Files changed in the last 5 commits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review src/user/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A specific directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review --staged&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Final check right before committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review --branch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current branch vs main, before opening a PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review --staged --fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-fix what it finds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Dynamic context injection.&lt;/strong&gt; A &lt;code&gt;!`command`&lt;/code&gt; placeholder runs &lt;em&gt;before&lt;/em&gt; Claude sees the skill and gets replaced with its output. My skill uses it to enumerate the rule files and changed files up front:&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="p"&gt;-&lt;/span&gt; Project rules: !&lt;span class="sb"&gt;`find .claude/rules -name "*.md" | sort`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Staged files: !&lt;span class="sb"&gt;`git diff --name-only --cached`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Claude Code client runs these commands during preprocessing; the model receives only the expanded results as part of the skill instructions. That removes an entire class of "the model forgot to check X first" failures.&lt;/p&gt;

&lt;p&gt;📎 Full working example: &lt;a href="///files/claude-code-skills-guide-teaching-ai-your-workflow/review-code.md"&gt;code-review SKILL.md&lt;/a&gt; — save it as &lt;code&gt;.claude/skills/code-review/SKILL.md&lt;/code&gt; in your project. The directory name is what creates the &lt;code&gt;/code-review&lt;/code&gt; command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Claude Code already ships a bundled &lt;code&gt;/code-review&lt;/code&gt; skill. Adding your own &lt;code&gt;code-review&lt;/code&gt; skill at the personal or project level overrides the bundled version—which is exactly what I want here: a review driven by &lt;em&gt;my&lt;/em&gt; rule files, not a generic one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why This Skill Is Powerful
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Rule-driven checklists&lt;/strong&gt; — The skill loads &lt;code&gt;.claude/rules/&lt;/code&gt; dynamically instead of hardcoding policies, so the same skill works in every project and stays aligned with the current rule files.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Severity Level definitions&lt;/strong&gt; — CRITICAL/WARNING/SUGGESTION priorities prevent getting lost in minor issues.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Explicit execution process&lt;/strong&gt; — A five-step procedure makes the review process more consistent.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Example Output
&lt;/h2&gt;

&lt;p&gt;Running &lt;code&gt;/code-review&lt;/code&gt; in the terminal produces results like this:&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="gt"&gt;&amp;gt; /code-review src/user/api/user_router.py&lt;/span&gt;

🔍 Reviewing: src/user/api/user_router.py

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

&lt;span class="gu"&gt;### 🚨 CRITICAL (2)&lt;/span&gt;

&lt;span class="gs"&gt;**Line 45**&lt;/span&gt;: Direct Repository import detected
&lt;span class="p"&gt;  -&lt;/span&gt; Found: &lt;span class="sb"&gt;`from src.user.repositories.user_repository import UserRepository`&lt;/span&gt;
&lt;span class="p"&gt;  -&lt;/span&gt; Fix: Remove this import. Use Service layer instead.

&lt;span class="gs"&gt;**Line 78**&lt;/span&gt;: Business logic in API layer
&lt;span class="p"&gt;  -&lt;/span&gt; Found: &lt;span class="sb"&gt;`if user.age &amp;gt;= 18 and user.verified:`&lt;/span&gt;
&lt;span class="p"&gt;  -&lt;/span&gt; Fix: Move this validation to UserService.validate_user_eligibility()

&lt;span class="gu"&gt;### ⚠️ WARNING (1)&lt;/span&gt;

&lt;span class="gs"&gt;**Line 23**&lt;/span&gt;: Service manually instantiated
&lt;span class="p"&gt;  -&lt;/span&gt; Found: &lt;span class="sb"&gt;`service = UserService()`&lt;/span&gt;
&lt;span class="p"&gt;  -&lt;/span&gt; Fix: Use &lt;span class="sb"&gt;`service: UserService = Depends(get_user_service)`&lt;/span&gt;

&lt;span class="gu"&gt;### 💡 SUGGESTION (1)&lt;/span&gt;

&lt;span class="gs"&gt;**Line 12**&lt;/span&gt;: Consider adding return type hint
&lt;span class="p"&gt;  -&lt;/span&gt; Current: &lt;span class="sb"&gt;`async def get_user(user_id: int):`&lt;/span&gt;
&lt;span class="p"&gt;  -&lt;/span&gt; Suggested: &lt;span class="sb"&gt;`async def get_user(user_id: int) -&amp;gt; StandardResponse[UserResponse]:`&lt;/span&gt;
&lt;span class="p"&gt;
---&lt;/span&gt;
Summary: 2 critical, 1 warning, 1 suggestion
Run &lt;span class="sb"&gt;`/code-review --fix`&lt;/span&gt; to auto-fix applicable issues.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command produces a repeatable first-pass architecture review based on your project's documented rules. It doesn't replace human review—but it catches routine violations before a pull request ever reaches another developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Note: Review Skills Before Trusting Them
&lt;/h2&gt;

&lt;p&gt;The same two features that make skills powerful make them worth auditing. Skills are executable workflow definitions, not passive documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;allowed-tools&lt;/code&gt; pre-approves tool usage for the duration of the skill—no permission prompts.&lt;/li&gt;
&lt;li&gt;  Dynamic context expressions like &lt;code&gt;!`command`&lt;/code&gt; run &lt;strong&gt;during preprocessing&lt;/strong&gt;, before the rendered skill content ever reaches the model.&lt;/li&gt;
&lt;li&gt;  A skill checked into an unfamiliar repository deserves a read before you accept workspace trust. (You can disable shell preprocessing entirely with the &lt;code&gt;disableSkillShellExecution&lt;/code&gt; setting.)&lt;/li&gt;
&lt;li&gt;  Keep permissions narrow: &lt;code&gt;Bash(git *)&lt;/code&gt; beats &lt;code&gt;Bash(*)&lt;/code&gt;, and list only the tools the procedure actually needs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Where Skills Provide the Most Value
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ① Consistent Code Quality
&lt;/h3&gt;

&lt;p&gt;Human reviewers vary by mood and energy. A well-defined Skill applies the same checklist every time, reducing variation and making common omissions less likely.&lt;/p&gt;

&lt;h3&gt;
  
  
  ② Encapsulating Complex Workflows
&lt;/h3&gt;

&lt;p&gt;Tasks that touch multiple files (adding a new API endpoint requires Router, Service, Schema, and Test files) can be bundled into a single Skill, reducing the chance of missing a step.&lt;/p&gt;

&lt;h3&gt;
  
  
  ③ Knowledge as an Asset
&lt;/h3&gt;

&lt;p&gt;Embed your design philosophy into Skill files and share via Git. Junior developers can generate code that is consistently aligned with documented senior guidelines. And because Skills follow an open standard, the SOPs you encode aren't locked into one tool.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Practical Patterns
&lt;/h2&gt;

&lt;p&gt;These are skills currently in my &lt;code&gt;~/.claude/skills/&lt;/code&gt; and project &lt;code&gt;.claude/skills/&lt;/code&gt; directories—not hypotheticals:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill Command&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;/code-review&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Check architecture violations against &lt;code&gt;.claude/rules/&lt;/code&gt; with severity levels and &lt;code&gt;--fix&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;/commit-push&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stage, generate a conventional commit message, confirm, push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;/create-post&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scaffold a new blog post following every content convention (slug rules, image folders, frontmatter schema)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;/feature-image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crop and convert cover images to 16:9 WebP under a size budget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;/review-skill&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The meta one: audit &lt;code&gt;SKILL.md&lt;/code&gt; files against the open standard, with &lt;code&gt;--fix&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the pattern in the last row—once your process knowledge lives in files, you can write skills that maintain other skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Key Tips for Designing Skills
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Craft your description carefully&lt;/strong&gt; — It's the primary signal Claude uses to decide when to load a Skill automatically. Describe both what the skill does and when to use it: "Review code for Clean Architecture compliance" beats "Code review."&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Link to Rules&lt;/strong&gt; — Instead of duplicating policies inside the skill, load them: &lt;code&gt;.claude/rules/&lt;/code&gt; is the single source and the skill is the procedure that applies it.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Make checklists explicit&lt;/strong&gt; — "Review this code" produces inconsistent results. "Check these 5 things" delivers reliability.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Define Severity Levels&lt;/strong&gt; — Not all issues are equal. Include priority criteria in your Skill.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Add verification steps&lt;/strong&gt; — Always end with "verify the modified code builds" or "run lint" as a final check.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Keep &lt;code&gt;SKILL.md&lt;/code&gt; lean&lt;/strong&gt; — Under ~500 lines. Move deep reference material to &lt;code&gt;references/&lt;/code&gt; files that load on demand; the skill body occupies context for the whole session.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Control the trigger&lt;/strong&gt; — Side-effect workflows (deploy, commit, publish) get &lt;code&gt;disable-model-invocation: true&lt;/code&gt;. Guardrails belong in frontmatter, not in hope.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Combine with MCP&lt;/strong&gt; — If you have MCP servers connected to external tools (GitHub, databases), you can write instructions like "query the DB schema before writing code" for smarter automation.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Claude Code Skills turn repeated instructions into &lt;strong&gt;reusable, version-controlled workflows&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Their quality depends less on clever prompting than on how clearly you've defined the process Claude should follow.&lt;/p&gt;

&lt;p&gt;If your team repeatedly explains the same conventions during code reviews, those conventions are good candidates for a Skill. Start with one narrow workflow, test it against real tasks, and refine it as your process changes.&lt;/p&gt;

&lt;p&gt;In the next article, we'll explore &lt;strong&gt;Custom Agents&lt;/strong&gt;—how to build AI that autonomously decides when to use which Skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Series:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://dev.to/enforcing-architecture-consistency-with-claude-rules-in-fastapi/"&gt;Enforcing Team Architecture with .claude/rules in Claude Code (FastAPI Practical Guide)&lt;/a&gt; — Teaching AI your policies&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Skills Guide&lt;/strong&gt; — Teaching AI your procedures &lt;em&gt;(this article)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/claude-code-agents-guide-how-skills-power-subagents/"&gt;Claude Code Agents Guide: How Skills Power Your Subagents&lt;/a&gt; — Teaching AI when to act&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://jamongx.com/claude-code-skills-guide-teaching-ai-your-workflow/" rel="noopener noreferrer"&gt;jamongx.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
