<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://awslabs.github.io/cli-agent-orchestrator/blog</id>
    <title>CAO Blog</title>
    <updated>2026-09-07T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://awslabs.github.io/cli-agent-orchestrator/blog"/>
    <subtitle>Tutorials, deep dives, and community stories about CLI Agent Orchestrator.</subtitle>
    <icon>https://awslabs.github.io/cli-agent-orchestrator/img/favicon.ico</icon>
    <rights>Copyright © 2026 Amazon.com, Inc. or its affiliates.</rights>
    <entry>
        <title type="html"><![CDATA[An LLM wrote my agent profile. It looked perfect. It was wrong.]]></title>
        <id>https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile</id>
        <link href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile"/>
        <updated>2026-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Machine-generated agent profiles fail in ways you can't see. A walkthrough of the Profiles web UI as the review gate they were missing.]]></summary>
        <content type="html"><![CDATA[<p>I broke my own agent twice in one week. Once by hand, once with help from a very confident language model. This post is about both breaks, and about the Profiles tab in the CAO Web UI that turns machine-written profiles from "looks right" into "checked."</p>
<!-- -->
<p>Everything below was run against CAO v2.5.1.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="act-one-i-did-it-by-hand">Act one: I did it by hand<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#act-one-i-did-it-by-hand" class="hash-link" aria-label="Direct link to Act one: I did it by hand" title="Direct link to Act one: I did it by hand" translate="no">​</a></h2>
<p>An agent profile in CAO is a small markdown file. YAML frontmatter on top (name, provider, model, allowed tools, MCP servers), system prompt below. The <a class="" href="https://awslabs.github.io/cli-agent-orchestrator/docs/features/profiles">profiles docs</a> have the full schema.</p>
<p>I wanted a code-review agent with a stricter tool list. So I copied a built-in profile, opened an editor, and changed it. A five-minute job, in theory. I renamed the file, tweaked the prompt, saved, launched.</p>
<p>The agent came up with the old name. The <code>name:</code> field inside the frontmatter still said the old name, and the frontmatter wins. I had renamed the file like it was 2019 and files meant something.</p>
<p>Ten minutes gone. Annoying, but fair. I typed it, I own it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="act-two-i-asked-an-llm-like-a-modern-person">Act two: I asked an LLM, like a modern person<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#act-two-i-asked-an-llm-like-a-modern-person" class="hash-link" aria-label="Direct link to Act two: I asked an LLM, like a modern person" title="Direct link to Act two: I asked an LLM, like a modern person" translate="no">​</a></h2>
<p>The obvious next step: don't write config by hand. I asked my coding assistant to generate the profile for me. I pasted the schema docs and said "make me a strict code-review agent."</p>
<p>It produced a beautiful profile. Clean YAML, a thorough prompt, severity levels, an output format. I admired it for a moment. Then I looked closer.</p>
<!-- -->
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">---</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> strict</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">reviewer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">description</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> A strict code review agent that enforces high standards for code quality</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> security</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> and best practices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">model_id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> us.anthropic.claude</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">sonnet</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">4</span><span class="token punctuation" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20250514</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">tools</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> think</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> file_read</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> file_write</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> execute_bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> list_directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">system_prompt</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">  You are a strict, senior code reviewer. Your job is to review code changes with exacting standards. You do not approve code lightly.</span><br></div><div class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">  [... forty more genuinely good lines ...]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">---</span><br></div></code></pre></div></div>
<p>Count the problems. I found none at first. Then I pasted it into the validator (next section), which found two, and taught me something about my own review in the process:</p>
<ul>
<li class=""><code>model_id:</code> is not a field. The schema calls it <code>model</code>. Close only counts in horseshoes.</li>
<li class=""><code>system_prompt:</code> in the frontmatter is the best one. In CAO's format, the system prompt IS the markdown body below the frontmatter. The model wrote a genuinely good prompt and then filed the entire essay inside a YAML string, like mailing a letter by writing it on the envelope.</li>
</ul>
<p>And the part that humbled me: before running the validator, my own careful reading had flagged <code>tools:</code> as a third invented field. It is not. <code>tools</code> is a perfectly legitimate property in the schema. The machine hallucinated two fields; the human reviewing it hallucinated a third. Neither of us is a schema.</p>
<p>Every line of that YAML parses. Nothing complains. The prompt content itself is honestly better than what I wrote by hand. And the profile is wrong in ways I could not reliably see, because it looked like something a careful person wrote. I had no reason to check, so I did not check. And when I did check by eye, I got the answer wrong anyway.</p>
<p>The mistake did not go away when I stopped typing. It got better at hiding.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-actual-lesson">The actual lesson<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#the-actual-lesson" class="hash-link" aria-label="Direct link to The actual lesson" title="Direct link to The actual lesson" translate="no">​</a></h2>
<p>Generating config got automated. Checking it did not. The bottleneck moved from writing to reviewing, and my review process was "gaze at it warmly."</p>
<p>That is the problem the Profiles tab addresses. It is not an editor with buttons. It is the review gate that machine-written profiles were missing.</p>
<p>Concretely, it gives every profile the same checks before it can run, whoever wrote it: schema validation at save time with findings in plain words, a live preview that renders the final document as you type, a clone flow that rewrites the frontmatter <code>name</code> so a copy cannot silently keep its source's identity, and ranked search so the profile you need gets found instead of written again. None of this makes generation better. The benefit is where failures land: a wrong profile now fails at save time, in front of you, instead of at run time inside an agent that looks like it is working.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-walkthrough">The walkthrough<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#the-walkthrough" class="hash-link" aria-label="Direct link to The walkthrough" title="Direct link to The walkthrough" translate="no">​</a></h2>
<p>You need CAO installed (see the <a class="" href="https://awslabs.github.io/cli-agent-orchestrator/docs/intro">getting started guide</a>) and the server running:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cao-server</span><br></div></code></pre></div></div>
<p>Open the Web UI at <code>http://localhost:9889</code> and press <code>Alt+2</code> for the Profiles tab. Everything below happens in the browser.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-paste-the-machines-homework">Step 1: paste the machine's homework<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#step-1-paste-the-machines-homework" class="hash-link" aria-label="Direct link to Step 1: paste the machine's homework" title="Direct link to Step 1: paste the machine's homework" translate="no">​</a></h3>
<p>Every local profile has an <strong>Edit</strong> button that opens the raw source in a modal. (Built-ins are read-only -- step 4 covers the supported way to get a local copy.) The editor shows placeholders like <code>${API_KEY}</code> exactly as written in the file; resolved values stay out of the editing session.</p>
<p>I opened a local profile and pasted the model's output over it:</p>
<p><img decoding="async" loading="lazy" alt="The raw source editor with the LLM-generated profile pasted in, model_id and tools visible in the frontmatter" src="https://awslabs.github.io/cli-agent-orchestrator/assets/images/editor-pasted-3cdba8dc802d89d72cf437e31497b7e3.png" width="1310" height="927" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-watch-the-red-border-do-its-job">Step 2: watch the red border do its job<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#step-2-watch-the-red-border-do-its-job" class="hash-link" aria-label="Direct link to Step 2: watch the red border do its job" title="Direct link to Step 2: watch the red border do its job" translate="no">​</a></h3>
<p>On save, validation refused, in plain words: <strong>Additional properties are not allowed ('model_id', 'system_prompt' were unexpected)</strong>. The two invented fields, named exactly, the editor outlined in red, and the save blocked until they are gone.</p>
<p><img decoding="async" loading="lazy" alt="Validation findings rejecting model_id and system_prompt as unexpected properties, with the editor outlined in red and the save blocked" src="https://awslabs.github.io/cli-agent-orchestrator/assets/images/validation-findings-04bc6362ba77a30974d9739a0d819f7e.png" width="1274" height="901" class="img_ev3q"></p>
<p>Thirty seconds. By hand, this took me a morning coffee and some light swearing -- and as established above, my by-hand answer was also wrong.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-fix-it-with-the-guardrails-watching">Step 3: fix it with the guardrails watching<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#step-3-fix-it-with-the-guardrails-watching" class="hash-link" aria-label="Direct link to Step 3: fix it with the guardrails watching" title="Direct link to Step 3: fix it with the guardrails watching" translate="no">​</a></h3>
<p>I renamed <code>model_id</code> to <code>model</code> and moved the prompt out of the YAML string into the document body where it belongs. Save accepted it.</p>
<p>The same checking runs in the create flow, before a bad profile ever exists. <strong>New profile → From template</strong> gives a config form with per-field validation -- required fields get the red border up front -- and a live preview that renders the final document as you type. What the preview shows is what gets saved:</p>
<p><img decoding="async" loading="lazy" alt="The from-template create form with per-field validation on required fields and the live preview pane rendering below" src="https://awslabs.github.io/cli-agent-orchestrator/assets/images/preview-pane-215429239833f42de2753398ffc726c2.png" width="1282" height="902" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-clone-instead-of-copy">Step 4: clone instead of copy<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#step-4-clone-instead-of-copy" class="hash-link" aria-label="Direct link to Step 4: clone instead of copy" title="Direct link to Step 4: clone instead of copy" translate="no">​</a></h3>
<p>Remember my act-one mistake, the file rename that did nothing? The <strong>Clone</strong> button handles the whole thing: it copies a built-in (built-ins are read-only, so clone is the supported path), asks for the new name, and rewrites the frontmatter <code>name:</code> field to match. The trap I fell into by hand is closed off in this flow.</p>
<p><img decoding="async" loading="lazy" alt="The clone dialog on a built-in profile, asking for the new name and noting the frontmatter name is updated to match" src="https://awslabs.github.io/cli-agent-orchestrator/assets/images/clone-dialog-4e9374dfb2b0891f7bc64a50c671d92d.png" width="1297" height="911" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-launch-it">Step 5: launch it<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#step-5-launch-it" class="hash-link" aria-label="Direct link to Step 5: launch it" title="Direct link to Step 5: launch it" translate="no">​</a></h3>
<p>Back in the list, my <code>strict-reviewer</code> shows up with a <code>local</code> badge, ranked search finds it by name or description, and launching it from the Agents tab gives me the agent I actually described, with the tool policy actually enforced.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-it-cost">What it cost<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#what-it-cost" class="hash-link" aria-label="Direct link to What it cost" title="Direct link to What it cost" translate="no">​</a></h2>
<p>Honesty section, because this blog asks for it. This surface went through seven rounds of maintainer review before it merged (<a href="https://github.com/awslabs/cli-agent-orchestrator/pull/692" target="_blank" rel="noopener noreferrer" class="">#692</a>). Most of the findings were async race conditions: a stale search result landing under a new query, a tab switch unmounting a save in flight, a settled preview surviving a template switch it should not have survived. We ended up extracting one shared staleness primitive and pinning each ordering with around 290 tests.</p>
<p>There is a joke in there somewhere about building a review gate and then being reviewed seven times through it. The maintainers found it before I did.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-takeaway">The takeaway<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#the-takeaway" class="hash-link" aria-label="Direct link to The takeaway" title="Direct link to The takeaway" translate="no">​</a></h2>
<p>If an LLM writes your agent profiles, and it probably does, a better generator is not the missing piece. What was missing is a place where any author's output, yours or the machine's, gets checked before it runs. That now ships in the box: <code>Alt+2</code>.</p>
<p>Try it, and if the validator catches your model inventing a field, I would genuinely love to hear which one it invented. There is a <a href="https://github.com/awslabs/cli-agent-orchestrator/discussions" target="_blank" rel="noopener noreferrer" class="">discussion board</a> for exactly that.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="about-the-author">About the author<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/2026/09/07/llm-wrote-my-agent-profile#about-the-author" class="hash-link" aria-label="Direct link to About the author" title="Direct link to About the author" translate="no">​</a></h2>
<p>Sujoy Datta Choudhury is a Software Development Engineer at Amazon Ads, where he works on real-time ad-serving systems, with over two decades of varied experience across FinTech and workflow orchestration. He contributed the Profiles surface to CLI Agent Orchestrator. His current interest is the reliability of LLM agents: how machine-generated configuration, plans, and code get verified before they run.</p>]]></content>
        <author>
            <name>Sujoy Datta Choudhury</name>
            <uri>https://github.com/sujoydc</uri>
        </author>
        <category label="Tutorial" term="Tutorial"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Welcome to the CAO blog]]></title>
        <id>https://awslabs.github.io/cli-agent-orchestrator/blog/welcome</id>
        <link href="https://awslabs.github.io/cli-agent-orchestrator/blog/welcome"/>
        <updated>2026-08-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why this blog exists, what belongs here, and how to publish a post.]]></summary>
        <content type="html"><![CDATA[<p>The reference documentation tells you what CAO does. It's a poor fit for the
other half of the story — the walkthrough that takes an hour, the design
decision that needs three diagrams to justify, the write-up of an orchestration
that worked on real work and the two that didn't. This blog is where that goes.</p>
<p>Anyone who contributes to CLI Agent Orchestrator can publish here. Posts live in
<code>docusaurus/blog/</code> and ship through the same pull request review as the rest of
the repository.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-belongs-here">What belongs here<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/welcome#what-belongs-here" class="hash-link" aria-label="Direct link to What belongs here" title="Direct link to What belongs here" translate="no">​</a></h2>
<ul>
<li class=""><strong>Tutorials and how-tos</strong> — a task followed end to end, with commands a reader
can run.</li>
<li class=""><strong>Deep dives</strong> — how a subsystem works and why it's built that way. Sessions,
the MCP server, and provider adapters all have more depth than their reference
pages carry.</li>
<li class=""><strong>Orchestration patterns in practice</strong> — <a class="" href="https://awslabs.github.io/cli-agent-orchestrator/docs/patterns/handoff">handoff</a>,
<a class="" href="https://awslabs.github.io/cli-agent-orchestrator/docs/patterns/assign">assign</a>, and
<a class="" href="https://awslabs.github.io/cli-agent-orchestrator/docs/patterns/send-message">send-message</a> composed into something real.</li>
<li class=""><strong>Case studies</strong> — what you built, what it cost, and where it fell over. The
failures are the useful part.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-doesnt">What doesn't<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/welcome#what-doesnt" class="hash-link" aria-label="Direct link to What doesn't" title="Direct link to What doesn't" translate="no">​</a></h2>
<p><strong>Release announcements.</strong> <a href="https://github.com/awslabs/cli-agent-orchestrator/blob/main/CHANGELOG.md" target="_blank" rel="noopener noreferrer" class=""><code>CHANGELOG.md</code></a> and
<a href="https://github.com/awslabs/cli-agent-orchestrator/releases" target="_blank" rel="noopener noreferrer" class="">GitHub Releases</a> already carry them, and a blog that mirrors a
changelog becomes a stale changelog. We're deliberately not doing that.</p>
<p><strong>Marketing.</strong> No product pitches, no competitor comparisons, no claims a reader
can't verify from the repository.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="publishing-a-post">Publishing a post<a href="https://awslabs.github.io/cli-agent-orchestrator/blog/welcome#publishing-a-post" class="hash-link" aria-label="Direct link to Publishing a post" title="Direct link to Publishing a post" translate="no">​</a></h2>
<p>The <a href="https://github.com/awslabs/cli-agent-orchestrator/blob/main/CONTRIBUTING.md#writing-a-blog-post" target="_blank" rel="noopener noreferrer" class="">contributing guide</a> has the mechanics: the file layout, the
front matter, registering yourself in <code>blog/authors.yml</code>, and the style rules the
build enforces. The short version is that a post is a directory, a Markdown
file, and a pull request.</p>
<p>If you're not sure whether an idea fits, open a
<a href="https://github.com/awslabs/cli-agent-orchestrator/discussions" target="_blank" rel="noopener noreferrer" class="">discussion</a> and ask before you write. It's a cheaper conversation
than a rejected draft.</p>]]></content>
        <author>
            <name>CAO Maintainers</name>
            <uri>https://github.com/awslabs/cli-agent-orchestrator</uri>
        </author>
        <category label="Community" term="Community"/>
    </entry>
</feed>