<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel>
<title>Blog — Egor Urvanov</title><link>https://www.urvanov.com/en/blog/</link><description>AI development, engineering management, communities</description><language>en</language>
<atom:link href="https://www.urvanov.com/en/rss.xml" rel="self" type="application/rss+xml" />
<item><title>Claude Code, Codex, Cursor and Hermes Agent: AI coding agents compared on one map</title><link>https://www.urvanov.com/en/blog/ai-in-code-harness-and-tools/</link><guid>https://www.urvanov.com/en/blog/ai-in-code-harness-and-tools/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>Claude Code or Codex, Cursor or Hermes Agent: where the agent runs, what it sees, which model it thinks with and what it costs — five harnesses side by side and which one to pick for the task. With links to the docs.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-harness-en"><div class="grp3" aria-label="Three groups of tools"><div class="gc pair"><span class="gk">vendor agents</span><div class="chips"><span class="chip">Claude Code</span><span class="vsw"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 9h15l-4-4M20 15H5l4 4"/></svg>nearly equivalent</span><span class="chip">Codex</span></div></div><div class="gc open"><span class="gk">open-source harnesses</span><div class="chips"><span class="chip">Hermes Agent</span></div><small class="alts">and alternatives: OpenCode, Aider, Cline, Goose</small><small>A harness of the same type with any model, via an API billed per token or locally on your own computer</small></div><div class="gc"><span class="gk">AI code editor</span><span class="chip">Cursor</span><small>AI-native IDE, models from several vendors</small></div><div class="gc chat"><span class="gk">AI assistant in the browser</span><span class="chip">ChatGPT, Claude</span><small>code runs in a sandbox, no project access</small></div></div><p class="cap">The <span class="drift sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg>snapshot</span> tag means the information is current as of September 2026 and may become outdated within a week.</p><section class="chapter" id="tasks"><h2><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg></span>Which harness for which task</h2><p class="why">The choice starts with the task. The two circles are model families, Claude and GPT: a product’s place on the map shows which models it works with. Claude Code and Codex are each tied to their own family, Cursor and chat sit in the overlap, and Hermes Agent fully covers Cursor and chat, partly overlaps Claude Code and Codex and reaches beyond both circles, connecting any model, including local ones<a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: local models via Ollama, llama.cpp, vLLM or LM Studio — “Ollama runs open-weight models locally with one command. Best for: quick local experimentation, privacy-sensitive work, offline use” — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><span class="drift"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg>notes · snapshot September 2026</span><div class="venn"><svg viewBox="0 0 920 540" role="img" aria-label="Two circles, Claude models and GPT models; Claude Code only in the Claude circle, Codex only in the GPT circle; Cursor and chat in the overlap; Hermes Agent fully contains Cursor and chat, partly overlaps Claude Code and Codex and extends beyond both circles; all inside the harness frame"><defs><clipPath id="hxXor-en" clipPathUnits="userSpaceOnUse"><path clip-rule="evenodd" d="M275,270 A150,150 0 1,0 575,270 A150,150 0 1,0 275,270 Z M345,270 A150,150 0 1,0 645,270 A150,150 0 1,0 345,270 Z"/></clipPath><clipPath id="hxGpt-en" clipPathUnits="userSpaceOnUse"><circle cx="495" cy="270" r="150"/></clipPath></defs><rect class="rg v-h" x="6" y="6" width="908" height="528" rx="36"/><text class="vts" x="890" y="40" text-anchor="end">every product has a harness</text><g clip-path="url(#hxXor-en)"><circle class="rg v-cc" cx="425" cy="270" r="150"/></g><g clip-path="url(#hxXor-en)"><circle class="rg v-cx" cx="495" cy="270" r="150"/></g><g clip-path="url(#hxGpt-en)"><circle class="rg v-sh" cx="425" cy="270" r="150"/></g><ellipse class="rg v-hm" cx="460" cy="340" rx="230" ry="130"/><circle class="rg v-cu" cx="460" cy="265" r="42"/><circle class="rg v-ch" cx="460" cy="365" r="44"/><circle class="vpt" cx="340" cy="175" r="5"/><path class="vld" d="M336,168 L200,100"/><text class="vtl" x="190" y="72" text-anchor="middle">Claude Code</text><text class="vts" x="190" y="90" text-anchor="middle">Claude models only</text><circle class="vpt" cx="580" cy="175" r="5"/><path class="vld" d="M584,168 L720,100"/><text class="vtl" x="730" y="72" text-anchor="middle">Codex</text><text class="vts" x="730" y="90" text-anchor="middle">GPT models only</text><text class="vtl" x="460" y="263" text-anchor="middle">Cursor</text><text class="vts" x="460" y="281" text-anchor="middle">editor</text><text class="vtl" x="460" y="358" text-anchor="middle">ChatGPT</text><text class="vtl" x="460" y="376" text-anchor="middle">Claude</text><text class="vts" x="460" y="393" text-anchor="middle">chat</text><text class="vts" x="300" y="505" text-anchor="middle">Claude models</text><text class="vts" x="620" y="505" text-anchor="middle">GPT models</text><text class="vtl" x="460" y="440" text-anchor="middle">Hermes Agent</text><text class="vts" x="460" y="458" text-anchor="middle">any model</text></svg></div><div style="margin-top:14px"></div><div class="tbl"><table><thead><tr><th>Task</th><th>Group</th></tr></thead><tbody><tr><td>One-off question without the repository</td><td>chat: ChatGPT or Claude</td></tr><tr><td>Change inside an open project, several files</td><td>agent in the editor</td></tr><tr><td>Task end to end without step-by-step involvement</td><td>Claude Code or Codex</td></tr><tr><td>Work in one project in a familiar editor with models from several vendors</td><td>Cursor</td></tr><tr><td>A custom harness on any model, billed per token</td><td>Hermes Agent</td></tr><tr><td>Prompt for production use via API with large inputs</td><td>data in XML tags</td></tr></tbody></table></div><div class="sublabel" style="margin-top:22px">Common questions</div><div class="qa"><div><h3>Claude Code or Codex</h3><p>They match in project access and actions and differ in the model (Claude and GPT) and in individual features that change from release to release. The choice is set by the model and plan the team already has.</p></div><div><h3>Cursor or Claude Code</h3><p>Cursor works inside an editor with an open project and lets you choose between models from different vendors. Claude Code takes a task from start to finish in the terminal, but only on Claude models.</p></div><div><h3>Hermes Agent or Claude Code</h3><p>Hermes Agent is an open-source harness: it connects any model, including local ones, and you pay per token. Claude Code is tied to the Claude family and a subscription. Choose Hermes for models from several vendors or your own model.</p></div><div><h3>Claude Code alternatives</h3><p>Of those covered here: Codex (the same design, GPT models), Cursor (an editor, models from several vendors) and Hermes Agent. <a href="https://opencode.ai" target="_blank" rel="noopener">OpenCode</a>, <a href="https://aider.chat" target="_blank" rel="noopener">Aider</a>, <a href="https://cline.bot" target="_blank" rel="noopener">Cline</a> and <a href="https://goose-docs.ai" target="_blank" rel="noopener">Goose</a> are built in a similar way.</p></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A task sets two requirements for a harness: whether it needs the project and which model family fits. Vendor agents work with one family, Cursor and chat offer a choice between Claude and GPT, and open-source harnesses take any model, including local ones.</div><div class="fg"><span class="fk">In general</span>First pick the group by the task, then the product within the group. Claude Code and Codex differ in the model and in individual harness features that change from release to release, yet conceptually they are built the same way. So what decides is the model and plan the team already has.</div><div class="fa"><span class="fk">Next step</span>Describe the task in one line and settle three conditions: does it need the project, does it need a human at every step, and does it need another vendor’s model or a local model. Pick the group by those conditions.</div></div></section><section class="chapter" id="stable"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg></span>What stays the same</h2><p class="why">Claude Code and Codex are competing products whose capabilities converge with every release. The gap between them is small, so this article relies on what remains constant.</p><div class="sc"><div><div class="sh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>Stable</div><ul><li>model family</li><li>how a harness is built</li><li>ways of working with an agent</li></ul></div><div class="mv"><div class="sh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg>Changes every week<a class="proof" href="https://code.claude.com/docs/en/changelog" target="_blank" rel="noopener" data-quote="Claude Code: 8 releases from 17 to 25 September 2026, from 2.1.275 to 2.1.283 — code.claude.com/docs/en/changelog" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/changelog" target="_blank" rel="noopener" data-quote="Codex: four CLI releases from 22 to 26 September 2026 and the new GPT-6 Sol and Luna models — learn.chatgpt.com/docs/changelog" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div><ul><li>features and modes</li><li>default autonomy settings</li><li>positioning</li><li>models, plans and limits</li></ul></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Eight Claude Code releases shipped between 17 and 25 September; four Codex releases and the new GPT-6 models shipped between 22 and 26 September.</div><div class="fg"><span class="fk">In general</span>A feature comparison of Claude Code and Codex goes out of date faster than anyone can make sense of it. Three things remain stable: the model family, how the harness is built and the ways of working with an agent.</div><div class="fa"><span class="fk">Next step</span>When choosing between Claude Code and Codex, base the decision on the model and plan already available to the team.</div></div></section><section class="chapter" id="harness"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 5-9 5-9-5z"/><path d="M3 13l9 5 9-5"/></svg></span>What a harness is</h2><p class="why">A model answers with text. The harness is everything around it: skills, tools, environment, the human in the loop. Every AI product has one, from a terminal agent to a browser chat<a class="proof" href="https://claude.com/blog/a-harness-for-every-task-dynamic-workflows-in-claude-code" target="_blank" rel="noopener" data-quote="Anthropic calls Claude Code a harness: the post “A harness for every task” — claude.com/blog/a-harness-for-every-task-dynamic-workflows-in-claude-code" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. What differs is the composition. The "Via API" column uses Hermes Agent as an example; there are many open-source harnesses, such as OpenCode, Aider, Cline and Goose, and they are built the same way.</p><span class="drift"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg>snapshot · September 2026</span><div class="hx" aria-label="Harness layers by column"><div class="hx-row h"><div></div><div class="hh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6L3 12l6 6M15 6l6 6-6 6"/></svg><span>Via API</span><small>Hermes Agent · public API</small></div><div class="hh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16v10H4z M2 19h20"/></svg><span>Enterprise</span><small>Claude Code · Codex · private API</small></div><div class="hh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 19H17Q21 19 21 15Q21 11.5 17.5 11Q16.5 6.5 12 6.5Q8 6.5 6.8 10.5Q3 11 3 15Q3 19 7 19Z"/></svg><span>Cloud</span><small>Claude Code · Codex</small></div><div class="hh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H9l-5 4z"/></svg><span>Chat</span><small>ChatGPT · Claude</small></div></div><div class="hx-row"><div class="rl">Human</div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg><span class="cap2">along / at the end</span><span class="ps"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/security" target="_blank" rel="noopener" data-quote="Hermes Agent: for dangerous commands “the user must explicitly approve it”; sessions without a human use unattended_mode — hermes-agent.nousresearch.com/docs/user-guide/security" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg><span class="cap2">along / at the end</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/permission-modes" target="_blank" rel="noopener" data-quote="Claude Code: “In Manual mode, Claude Code stops and asks you before most actions… In auto mode, a second model, the classifier, reviews actions instead of you” — code.claude.com/docs/en/permission-modes" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/sandboxing" target="_blank" rel="noopener" data-quote="Codex: “The agent works inside the sandbox by default and asks when it needs to go beyond that boundary” — learn.chatgpt.com/docs/sandboxing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg><span class="cap2">along / at the end</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/claude-code-on-the-web" target="_blank" rel="noopener" data-quote="Claude Code: “You pick a cloud session&#39;s permission mode from the mode dropdown, both when you create the task and while the session runs” — code.claude.com/docs/en/claude-code-on-the-web" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/cloud" target="_blank" rel="noopener" data-quote="Codex: “Give longer tasks dedicated environments and let them continue while you work on something else” — learn.chatgpt.com/docs/cloud" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div title="differs from enterprise" class="diff c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg><span class="cap2">every step</span></div></div><div class="hx-row"><div class="rl">Environment</div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/></svg><span class="cap2">your computer</span><span class="ps"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/security" target="_blank" rel="noopener" data-quote="Hermes Agent: the default backend is “local — runs on host”, commands run on your computer — hermes-agent.nousresearch.com/docs/user-guide/security" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/></svg><span class="cap2">your computer</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “Desktop scheduled tasks run on your computer, with direct access to your local files and tools” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener" data-quote="Codex: “Codex can inspect files, make edits, and run the tools already installed on your computer” — learn.chatgpt.com/docs/codex/cli" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div title="differs from enterprise" class="diff c part"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 19H17Q21 19 21 15Q21 11.5 17.5 11Q16.5 6.5 12 6.5Q8 6.5 6.8 10.5Q3 11 3 15Q3 19 7 19Z"/></svg><span class="cap2">vendor VM</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/claude-code-on-the-web" target="_blank" rel="noopener" data-quote="Claude Code: “Isolated virtual machines: each session runs in an isolated, Anthropic-managed VM” — code.claude.com/docs/en/claude-code-on-the-web" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/cloud" target="_blank" rel="noopener" data-quote="Codex: “Run tasks in isolated cloud environments, work in parallel, and start work from the web, GitHub, GitLab, Linear, or Slack” — learn.chatgpt.com/docs/cloud" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div title="differs from enterprise" class="diff c part"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/></svg><span class="cap2">sandbox</span><span class="ps"><a class="proof" href="https://support.claude.com/en/articles/12111783-create-and-edit-files-with-claude" target="_blank" rel="noopener" data-quote="Claude: “When Claude executes code or creates files, it operates within an isolated, sandboxed container” — support.claude.com/en/articles/12111783" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/8437071-data-analysis-with-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: for data analysis it writes and runs Python in an isolated environment with no external requests. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/8437071" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div></div><div class="hx-row"><div class="rl">Tools</div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M7 9l3 3-3 3M13 16h4"/></svg><span class="ps"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/features/overview" target="_blank" rel="noopener" data-quote="Hermes Agent: built-in tools — “web search, terminal execution, file editing, memory, delegation” — hermes-agent.nousresearch.com/docs/user-guide/features/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M7 9l3 3-3 3M13 16h4"/></svg><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “reads your codebase, edits files, runs commands, and integrates with your development tools” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener" data-quote="Codex: “Inspect code, make changes, run commands, and automate repeatable work without leaving your terminal” — learn.chatgpt.com/docs/codex/cli" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M7 9l3 3-3 3M13 16h4"/></svg><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “reads your codebase, edits files, runs commands, and integrates with your development tools” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener" data-quote="Codex: “Inspect code, make changes, run commands, and automate repeatable work without leaving your terminal” — learn.chatgpt.com/docs/codex/cli" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div title="differs from enterprise" class="diff c part"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M7 9l3 3-3 3M13 16h4"/></svg><span class="cap2">connectors</span><span class="ps"><a class="proof" href="https://support.claude.com/en/articles/11176164-use-connectors-to-extend-claude-s-capabilities" target="_blank" rel="noopener" data-quote="Claude: “Connectors let Claude access your apps and services, retrieve your data, and take actions within connected services” — support.claude.com/en/articles/11176164" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/11487775-connected-apps-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: “An app connects ChatGPT to an external service, such as Google Drive or Slack, so it can access information or perform supported actions” — help.openai.com/en/articles/11487775" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div></div><div class="hx-row"><div class="rl">Skills</div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.2 5.8L20 11l-5.8 2.2L12 19l-2.2-5.8L4 11l5.8-2.2z"/></svg><span class="ps"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/features/skills" target="_blank" rel="noopener" data-quote="Hermes Agent: skills are “on-demand knowledge documents the agent can load when needed”, following agentskills.io — hermes-agent.nousresearch.com/docs/user-guide/features/skills" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.2 5.8L20 11l-5.8 2.2L12 19l-2.2-5.8L4 11l5.8-2.2z"/></svg><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “Each surface connects to the same underlying Claude Code engine, so your repo&#39;s CLAUDE.md files, settings, and MCP servers work across all of them” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/customization/overview" target="_blank" rel="noopener" data-quote="Codex: “AGENTS.md gives Codex durable project guidance that travels with your repository”; “Skills give Codex reusable capabilities for repeatable workflows” — learn.chatgpt.com/docs/customization/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.2 5.8L20 11l-5.8 2.2L12 19l-2.2-5.8L4 11l5.8-2.2z"/></svg><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “Each surface connects to the same underlying Claude Code engine, so your repo&#39;s CLAUDE.md files, settings, and MCP servers work across all of them” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/customization/overview" target="_blank" rel="noopener" data-quote="Codex: “AGENTS.md gives Codex durable project guidance that travels with your repository”; “Skills give Codex reusable capabilities for repeatable workflows” — learn.chatgpt.com/docs/customization/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l2.2 5.8L20 11l-5.8 2.2L12 19l-2.2-5.8L4 11l5.8-2.2z"/></svg><span class="ps"><a class="proof" href="https://support.claude.com/en/articles/12512180-use-skills-in-claude" target="_blank" rel="noopener" data-quote="Claude: “Skills extend Claude&#39;s capabilities by giving it access to specialized knowledge and workflows” — support.claude.com/en/articles/12512180" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/20001066-skills-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: skills are reusable workflows with instructions, examples and code, on Business, Enterprise and Edu plans. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/20001066" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div></div><div class="hx-row"><div class="rl">Model</div><div title="differs from enterprise" class="diff c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg><span class="cap2">any · API at $/token or local</span><span class="ps"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: “works with any OpenAI-compatible API endpoint”; with a provider key “requests are billed pay-per-token against that key&#39;s organization (standard API pricing)” — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: local models via Ollama, llama.cpp, vLLM or LM Studio — “Ollama runs open-weight models locally with one command. Best for: quick local experimentation, privacy-sensitive work, offline use” — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg><span class="cap2">Claude / GPT · private API, plan</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “Most surfaces require a Claude subscription or Anthropic Console account” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/pricing" target="_blank" rel="noopener" data-quote="Codex: “ChatGPT Work and Codex are included in your ChatGPT Free, Go, Plus, Pro, Business, Edu, or Enterprise plan” — learn.chatgpt.com/docs/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg><span class="cap2">Claude / GPT · private API, plan</span><span class="ps"><a class="proof" href="https://code.claude.com/docs/en/claude-code-on-the-web" target="_blank" rel="noopener" data-quote="Claude Code: “Cloud sessions are available on Pro, Max, and Team plans, and for Enterprise users with premium seats” — code.claude.com/docs/en/claude-code-on-the-web" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/pricing" target="_blank" rel="noopener" data-quote="Codex: “ChatGPT Work and Codex are included in your ChatGPT Free, Go, Plus, Pro, Business, Edu, or Enterprise plan” — learn.chatgpt.com/docs/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div title="differs from enterprise" class="diff c"><svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg><span class="cap2">Claude / GPT, free / plan</span></div></div></div><div class="legend"><span><i class="dif"></i>differs from enterprise</span><span><i class="full"></i>yes</span><span><i class="part"></i>partly</span></div><div class="sublabel" style="margin-top:22px">Chat and agent</div><div class="qa"><div><h3>How Claude Code differs from Claude in chat</h3><p>The model family is the same; the harness differs. Chat answers in a conversation and does not see your project. Claude Code reads code, edits files and runs commands in the project: in the terminal, an editor, the desktop app or a browser. <a href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener">Docs</a></p></div><div><h3>How Codex differs from ChatGPT</h3><p>The same rule applies: the GPT models are shared, the environment differs. ChatGPT holds a conversation without project access; Codex works with code and runs commands.</p></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The four types differ in two properties: where code runs and how model access works. Open-source and enterprise run on your computer and differ only in model access, which is where the cost difference comes from.</div><div class="fg"><span class="fk">In general</span>Local types fit work with files and secrets on your computer, the cloud fits long and parallel tasks, chat fits tasks without project access. Constraints narrow the choice: an enterprise plan is not available in every jurisdiction<a class="proof" href="https://www.anthropic.com/supported-countries" target="_blank" rel="noopener" data-quote="Anthropic: “To the extent permitted by law, Anthropic reserves the right to not provide its products or services to entities whose majority direct or indirect ownership is attributable to nations other than those listed in our Supported Regions Policy” — anthropic.com/supported-countries" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Decide whether the task needs files on your computer, whether the agent should work without you, and which model you can use. The first points to a local type, the second to the cloud, neither to chat.</div></div></section><section class="chapter" id="compare"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg></span>What they see and do</h2><span class="drift"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg>snapshot · September 2026</span><div class="cv" aria-label="What it sees · What it does on its own · Models"><div class="cv-h"><span></span><span class="cv-hi" title="What it sees" aria-label="What it sees"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg></span><span class="cv-hi" title="What it does on its own" aria-label="What it does on its own"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L3 18l3 3 6.3-6.3a4 4 0 0 0 5.4-5.4l-2.5 2.5-2.4-.6-.6-2.4z"/></svg></span><span class="cv-hi" title="Models" aria-label="Models"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4"/></svg></span><span class="cv-hi" title="Cost" aria-label="Cost"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M14.5 9.2c-.4-.9-1.4-1.5-2.5-1.5-1.4 0-2.5.8-2.5 2s1.1 1.6 2.5 2 2.5.8 2.5 2-1.1 2-2.5 2c-1.2 0-2.2-.6-2.6-1.6M12 6v1.7M12 16.3V18"/></svg></span><span class="cv-hi" title="Sources" aria-label="Sources"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/></svg></span></div><div class="cv-r"><div class="cv-n">Hermes Agent</div><div class="cv-c"><svg class="cv-scope" viewBox="0 0 96 64" role="img" aria-label="The whole codebase"><title>The whole codebase</title><rect x="4" y="4" width="88" height="56" rx="4" class="on"/><rect x="18" y="14" width="60" height="36" rx="4" class="on"/><rect x="32" y="24" width="32" height="16" rx="4" class="on"/></svg></div><div class="cv-c cv-acts"><span class="cv-a on" title="Edits project files: yes" aria-label="Edits project files: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></span><span class="cv-a on" title="Runs commands on your computer: yes" aria-label="Runs commands on your computer: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span><span class="cv-a on" title="Runs the “edit → test → edit” loop on its own: yes" aria-label="Runs the “edit → test → edit” loop on its own: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><span class="cv-a" title="Works in an isolated environment: no" aria-label="Works in an isolated environment: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></svg></span></div><div class="cv-c"><span class="cv-v" title="Any model: via API or local" aria-label="Any model: via API or local"><i></i><i></i><i></i><i></i><i></i></span></div><div class="cv-c cv-cost"><span class="cv-usd" title="$/token or $0. API at provider rates or your own model locally" aria-label="$/token or $0. API at provider rates or your own model locally"><i class="on">$</i><i class="on">$</i><i class="on">$</i></span><span class="cv-cp"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: with a provider key “requests are billed pay-per-token against that key&#39;s organization (standard API pricing)” — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: local models via Ollama, llama.cpp, vLLM or LM Studio — “Ollama runs open-weight models locally with one command. Best for: quick local experimentation, privacy-sensitive work, offline use” — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="cv-c cv-p"><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/security" target="_blank" rel="noopener" data-quote="Hermes Agent: works in your project, the default backend is “local — runs on host” — hermes-agent.nousresearch.com/docs/user-guide/security" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://hermes-agent.nousresearch.com/docs/user-guide/features/overview" target="_blank" rel="noopener" data-quote="Hermes Agent: edits files, runs terminal commands, uses skills — hermes-agent.nousresearch.com/docs/user-guide/features/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://hermes-agent.nousresearch.com/docs/integrations/providers" target="_blank" rel="noopener" data-quote="Hermes Agent: connects to models from different providers via API — hermes-agent.nousresearch.com/docs/integrations/providers" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div class="cv-r"><div class="cv-n">Claude Code and Codex</div><div class="cv-c"><svg class="cv-scope" viewBox="0 0 96 64" role="img" aria-label="The whole codebase"><title>The whole codebase</title><rect x="4" y="4" width="88" height="56" rx="4" class="on"/><rect x="18" y="14" width="60" height="36" rx="4" class="on"/><rect x="32" y="24" width="32" height="16" rx="4" class="on"/></svg></div><div class="cv-c cv-acts"><span class="cv-a on" title="Edits project files: yes" aria-label="Edits project files: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></span><span class="cv-a on" title="Runs commands on your computer: yes" aria-label="Runs commands on your computer: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span><span class="cv-a on" title="Runs the “edit → test → edit” loop on its own: yes" aria-label="Runs the “edit → test → edit” loop on its own: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><span class="cv-a" title="Works in an isolated environment: no" aria-label="Works in an isolated environment: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></svg></span></div><div class="cv-c"><span class="cv-v" title="One model family: each product has its own" aria-label="One model family: each product has its own"><i></i></span></div><div class="cv-c cv-cost"><span class="cv-usd" title="from $20/mo. or $/token via API" aria-label="from $20/mo. or $/token via API"><i class="on">$</i><i class="on">$</i></span><span class="cv-cp"><a class="proof" href="https://claude.com/pricing" target="_blank" rel="noopener" data-quote="Claude: Pro is $20 a month billed monthly, Claude Code is included in Pro and Max; Enterprise is “Seat price + usage at API rates” — claude.com/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/pricing" target="_blank" rel="noopener" data-quote="Codex: “ChatGPT Work and Codex are included in your ChatGPT Free, Go, Plus, Pro, Business, Edu, or Enterprise plan”; the alternative is to “Pay for Codex usage based on API pricing” — learn.chatgpt.com/docs/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/6950777-what-is-chatgpt-plus" target="_blank" rel="noopener" data-quote="ChatGPT Plus is $20 a month. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/6950777" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="cv-c cv-p"><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “Claude Code is an agentic coding tool that reads your codebase” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener" data-quote="Codex: “Codex can inspect files, make edits, and run the tools already installed on your computer” — learn.chatgpt.com/docs/codex/cli" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://code.claude.com/docs/en/overview" target="_blank" rel="noopener" data-quote="Claude Code: “reads your codebase, edits files, runs commands, and integrates with your development tools” — code.claude.com/docs/en/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener" data-quote="Codex: “Inspect code, make changes, run commands, and automate repeatable work without leaving your terminal” — learn.chatgpt.com/docs/codex/cli" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div class="cv-r"><div class="cv-n">Cursor</div><div class="cv-c"><svg class="cv-scope" viewBox="0 0 96 64" role="img" aria-label="The open project"><title>The open project</title><rect x="4" y="4" width="88" height="56" rx="4" class="off"/><rect x="18" y="14" width="60" height="36" rx="4" class="on"/><rect x="32" y="24" width="32" height="16" rx="4" class="on"/></svg></div><div class="cv-c cv-acts"><span class="cv-a on" title="Edits project files: yes" aria-label="Edits project files: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></span><span class="cv-a on" title="Runs commands on your computer: yes" aria-label="Runs commands on your computer: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span><span class="cv-a" title="Runs the “edit → test → edit” loop on its own: no" aria-label="Runs the “edit → test → edit” loop on its own: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><span class="cv-a" title="Works in an isolated environment: no" aria-label="Works in an isolated environment: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></svg></span></div><div class="cv-c"><span class="cv-v" title="Models from 4 vendors" aria-label="Models from 4 vendors"><i></i><i></i><i></i><i></i></span></div><div class="cv-c cv-cost"><span class="cv-usd" title="from $20/mo. overage billed after" aria-label="from $20/mo. overage billed after"><i class="on">$</i><i class="on">$</i></span><span class="cv-cp"><a class="proof" href="https://cursor.com/pricing" target="_blank" rel="noopener" data-quote="Cursor: Pro is “$20 / mo.”; “Every plan includes a set amount of model usage. On-demand usage allows you to continue using models after your included amount is consumed, billed in arrears” — cursor.com/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="cv-c cv-p"><a class="proof" href="https://cursor.com/docs/agent/chat/checkpoints" target="_blank" rel="noopener" data-quote="Cursor: “Checkpoints save snapshots of your codebase during an Agent session” — cursor.com/docs/agent/chat/checkpoints" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://cursor.com/docs/agent/overview" target="_blank" rel="noopener" data-quote="Cursor: “Suggest edits to files and apply them automatically”, “Execute terminal commands and monitor output” — cursor.com/docs/agent/overview" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://cursor.com/docs/models" target="_blank" rel="noopener" data-quote="Cursor: “Cursor supports frontier models from OpenAI, Anthropic, Google, SpaceXAI, and more”; it also has its own models such as Composer 2.5 — cursor.com/docs/models" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://cursor.com/pricing" target="_blank" rel="noopener" data-quote="Cursor: “Every plan includes a set amount of model usage. On-demand usage allows you to continue using models after your included amount is consumed, billed in arrears” — cursor.com/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div class="cv-r"><div class="cv-n">Chat: ChatGPT, Claude</div><div class="cv-c"><svg class="cv-scope" viewBox="0 0 96 64" role="img" aria-label="Only the dialog and connected services"><title>Only the dialog and connected services</title><rect x="4" y="4" width="88" height="56" rx="4" class="off"/><rect x="18" y="14" width="60" height="36" rx="4" class="off"/><rect x="32" y="24" width="32" height="16" rx="4" class="on"/></svg></div><div class="cv-c cv-acts"><span class="cv-a" title="Edits project files: no" aria-label="Edits project files: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></span><span class="cv-a" title="Runs commands on your computer: no" aria-label="Runs commands on your computer: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span><span class="cv-a" title="Runs the “edit → test → edit” loop on its own: no" aria-label="Runs the “edit → test → edit” loop on its own: no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><span class="cv-a on" title="Works in an isolated environment: yes" aria-label="Works in an isolated environment: yes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></svg></span></div><div class="cv-c"><span class="cv-v" title="One model family: each product has its own" aria-label="One model family: each product has its own"><i></i></span></div><div class="cv-c cv-cost"><span class="cv-usd" title="free · from $20. subscription" aria-label="free · from $20. subscription"><i class="on">$</i></span><span class="cv-cp"><a class="proof" href="https://claude.com/pricing" target="_blank" rel="noopener" data-quote="Claude: Pro is $20 a month billed monthly, Claude Code is included in Pro and Max; Enterprise is “Seat price + usage at API rates” — claude.com/pricing" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/6950777-what-is-chatgpt-plus" target="_blank" rel="noopener" data-quote="ChatGPT Plus is $20 a month. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/6950777" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="cv-c cv-p"><a class="proof" href="https://support.claude.com/en/articles/11176164-use-connectors-to-extend-claude-s-capabilities" target="_blank" rel="noopener" data-quote="Claude: “Connectors let Claude access your apps and services, retrieve your data, and take actions within connected services” — support.claude.com/en/articles/11176164" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/11487775-connected-apps-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: “An app connects ChatGPT to an external service, such as Google Drive or Slack, so it can access information or perform supported actions” — help.openai.com/en/articles/11487775" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://support.claude.com/en/articles/12111783-create-and-edit-files-with-claude" target="_blank" rel="noopener" data-quote="Claude: “When Claude executes code or creates files, it operates within an isolated, sandboxed container” — support.claude.com/en/articles/12111783" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/8437071-data-analysis-with-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: for data analysis it writes and runs Python in an isolated environment with no external requests. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/8437071" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div class="cv-leg"><span class="cv-li"><span class="cv-usd sm"><i class="on">$</i></span><small>cheaper</small><span class="cv-usd sm"><i class="on">$</i><i class="on">$</i><i class="on">$</i></span><small>pricier · exact prices in the tooltip</small></span><span class="cv-li"><span class="cv-a on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></span><small>Edits project files</small></span><span class="cv-li"><span class="cv-a on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span><small>Runs commands on your computer</small></span><span class="cv-li"><span class="cv-a on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><small>Runs the “edit → test → edit” loop on its own</small></span><span class="cv-li"><span class="cv-a on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></svg></span><small>Works in an isolated environment</small></span></div></div><div class="sublabel" style="margin-top:22px">What is what</div><div class="qa three"><div><h3>What is Codex</h3><p>OpenAI’s agent for working with code: it takes a task, edits files and runs commands. It works in the terminal, in an editor extension and in the cloud, on GPT models. Project access is what sets it apart from the ChatGPT chat. <a href="https://learn.chatgpt.com/docs/codex/cli" target="_blank" rel="noopener">Docs</a></p></div><div><h3>What is Cursor</h3><p>A code editor with a built-in agent: the agent completes tasks on its own, runs terminal commands and edits code. It works in an open project and supports models from several vendors. <a href="https://cursor.com/docs/agent/overview" target="_blank" rel="noopener">Docs</a></p></div><div><h3>What is Hermes Agent</h3><p>An open-source agent from Nous Research. It runs on your computer, connects to different model providers, including Claude and open models, and can work with a local model. <a href="https://hermes-agent.nousresearch.com/docs/user-guide/features/overview" target="_blank" rel="noopener">Docs</a></p></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Claude Code and Codex match in project access and actions; they differ in the model and in individual harness features while staying conceptually the same.</div><div class="fg"><span class="fk">In general</span>Cursor stands out with its built-in editor and multi-vendor models, chat with its lack of project access. Between Claude Code and Codex, the model and plan determine the choice.</div><div class="fa"><span class="fk">Next step</span>If the task requires project files, chat is not suitable. Then choose by the model already available to the team.</div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/chatgpt-enterprise-usage-report/"><div class="k">Report</div><div class="t">ChatGPT Enterprise usage report</div><div class="d">Who in the company uses what</div></a><a href="/en/blog/ai-interviews-without-leading-questions/"><div class="k">Interviews</div><div class="t">Interviews without leading questions</div><div class="d">How to establish what employees actually need from AI</div></a></div></section><footer>Snapshot as of September 2026. Product claims follow the official docs of Anthropic, OpenAI, Cursor and Nous Research; the source is behind the icon next to each claim. Two OpenAI Help Center quotes are paraphrased.</footer></div>]]></content:encoded></item>
<item><title>How to run and analyze interviews about AI use: a 30-minute script, an analysis prompt and an Airtable table</title><link>https://www.urvanov.com/en/blog/ai-interviews-without-leading-questions/</link><guid>https://www.urvanov.com/en/blog/ai-interviews-without-leading-questions/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>A 30-minute call script, rules for staying on topic, a short company-wide questionnaire, interview analysis with ChatGPT or an agent using a ready prompt, and a said-versus-measured check against the report data.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-intervyu-en"><p class="credit">Interview design based on recommendations from <a href="https://t.me/Kseniya_Vasil" target="_blank" rel="noopener">@Kseniya_Vasil</a>. People, groups and numbers for the interviews come from the <a href="/en/blog/chatgpt-enterprise-usage-report/">ChatGPT Enterprise usage report</a>. It also holds the <a href="/en/blog/chatgpt-enterprise-usage-report/#why">business task</a>: what the company decides, who decides, and by which signs.</p><p class="lead-a">Here the analysis takes four steps: the conversation text goes to ChatGPT with the same prompt every time, the answer is copied into the person’s row, the table is grouped by difficulty, and repeats are checked with a company-wide questionnaire. What people say is compared with the report data. Below: the call script, the table and the <a href="#after">analysis prompt</a>.</p><div class="flow" aria-label="Two interview formats converge in one table"><div class="lane"><div class="lane-h" style="color:var(--c-chat)"><span class="dot" style="background:var(--c-chat)"></span>Voice</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2"/></svg><b>Call</b><small>30 min</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg><b><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> · <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a></b><small>Notes</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg><b>Transcript</b><small>Into Notes</small></span></div></div><div class="lane"><div class="lane-h" style="color:var(--c-work)"><span class="dot" style="background:var(--c-work)"></span>Text</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 8h8M8 12h8M8 16h5"/></svg><b>Questions</b><small>In chat</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg><b>Follow-up</b><small>1 message</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg><b>Chat log</b><small>Copied to Notes</small></span></div></div><div class="drop" style="grid-column:1 / -1" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M6 13l6 6 6-6"/></svg><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M6 13l6 6 6-6"/></svg></div><div class="sink"><div class="sink-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg><b><a href="https://airtable.com" target="_blank" rel="noopener">Airtable</a></b><span>Everything in one table</span><small>16 records</small></div><div class="mini"><span class="h">Name</span><span class="h nt">Notes</span><span class="h fm">Format</span><span class="h me">Frequency, self-reported</span><span class="h">Per report</span><span class="h stc">Status</span><span>Hana Sato</span><span class="nt">Host [00:00]: Think back to the last…</span><span class="fm"><span class="at c">voice</span></span><span><span class="at g">weekly</span></span><span><span class="at g">weekly</span></span><span class="stc"><span class="at g">Done</span></span><span>Pavel Novak</span><span class="nt">[27.09 10:15] Host: Describe the last…</span><span class="fm"><span class="at p">text</span></span><span><span class="at c">regularly</span></span><span><span class="at rd">doesn't use</span><span class="dif">≠</span></span><span class="stc"><span class="at g">Done</span></span><span>Nadia Rahimi</span><span class="nt">Host [00:00]</span><span class="fm"><span class="at c">voice</span></span><span><span class="at y">occasionally</span></span><span><span class="at y">occasionally</span></span><span class="stc"><span class="at g">Done</span></span></div></div></div><section class="chapter" id="format"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v6M12 9l-6 6v6M12 9l6 6v6"/></svg></span>Choosing a format</h2><div class="tbl"><table class="rate"><thead><tr><th>Criterion</th><th><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/></svg> Voice</th><th><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg> Text</th></tr></thead><tbody><tr><td>Depth of answers</td><td><span class="rt" aria-label="5 of 5"><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i></span></td><td><span class="rt" aria-label="2 of 5"><i class="on"></i><i class="on"></i><i></i><i></i><i></i></span></td></tr><tr><td>Follow-up in the moment</td><td><span class="rt" aria-label="5 of 5"><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i></span></td><td><span class="rt" aria-label="1 of 5"><i class="on"></i><i></i><i></i><i></i><i></i></span></td></tr><tr><td>How many people you can reach</td><td><span class="rt" aria-label="2 of 5"><i class="on"></i><i class="on"></i><i></i><i></i><i></i></span></td><td><span class="rt" aria-label="5 of 5"><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i></span></td></tr><tr><td>Respondent's time</td><td>30 min</td><td>10 min</td></tr><tr><td>Risk of going off topic</td><td><span class="rt w" aria-label="4 of 5"><i class="on"></i><i class="on"></i><i class="on"></i><i class="on"></i><i></i></span></td><td><span class="rt w" aria-label="1 of 5"><i class="on"></i><i></i><i></i><i></i><i></i></span></td></tr></tbody></table></div><p class="cap">Dots are a score from 1 to 5. For risk, more dots is worse.</p><div class="sublabel" style="margin-top:22px">Mix: the respondent picks the format</div><div class="mix" aria-label="Voice or text — the respondent chooses"><span class="mx">Invitation<small>By direct message</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="mx">Up for a call?<small>30 minutes</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><div class="mxo"><div><em>yes</em><span class="at c">voice</span> call with a note-taking assistant</div><div><em>no</em><span class="at p">text</span> same questions, one at a time, in chat</div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Voice scores 5 of 5 on depth, text scores 5 of 5 on reach. Each person picks the format.</div><div class="fg"><span class="fk">In general</span>When people choose the format themselves, fewer decline. The formats differ in depth: a call gives a detailed story with follow-ups, a chat gives short answers. So chat answers help find cases and topics, but they are not treated as equal to calls. Voice is the main format; chat is for those who cannot take a call. A company-wide questionnaire is a separate tool, written after the interviews.</div><div class="fa"><span class="fk">Next step</span>Offer both formats in one sentence in the invitation: "Shall we do a 30-minute call, or would you rather answer the questions in chat?"</div></div></section><section class="chapter" id="prep"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/></svg></span>Preparing for the meeting</h2><ul class="todo"><li><span class="box" aria-hidden="true"></span><div><b>Mention the note-taking assistant</b><span class="d">In the invitation and at the start of the call: the assistant takes notes and a transcript that only the team sees, and answers go into the report without names. With <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a>, no audio is kept</span></div></li><li><span class="box" aria-hidden="true"></span><div><b><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> or <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a></b><span class="d"><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> is connected to the calendar and joins the Google Meet or Zoom meeting on its own. <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a> works without a bot, using your computer audio, and keeps only the transcript and notes</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Airtable row created in advance</b><span class="d">Name, group and numbers from the <a href="/en/blog/chatgpt-enterprise-usage-report/#people">table of all people</a>, status "In progress", before the first message</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Guide open on a second screen</b><span class="d">Seven script blocks and a 30-minute timer</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>One host, no note-taking</b><span class="d"><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> or <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a> does the transcript, ChatGPT does the analysis</span></div></li></ul><div class="finding"><b>Takeaway</b><div class="fa"><span class="fk">Next step</span>Before the meeting, check that <a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> sees the meeting in the calendar or <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a> is running on your computer, and create the Airtable row, so the call is left with nothing but questions.</div></div></section><section class="chapter" id="script"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>A 30-minute script</h2><div class="tline" aria-label="30"><div style="flex:2;background:var(--c-none);color:var(--ink)">2</div><div style="flex:3;background:var(--c-light)">3</div><div style="flex:8;background:var(--c-chat)">8</div><div style="flex:5;background:var(--c-proj)">5</div><div style="flex:4;background:var(--c-team)">4</div><div style="flex:5;background:var(--c-work)">5</div><div style="flex:3;background:var(--c-none);color:var(--ink)">3</div></div><p class="cap">Minutes per block</p><ol class="script"><li><span class="sn" style="background:var(--c-none);color:var(--ink)">1</span><div><div class="st-t">Intro</div><div class="q">"I'm looking at how people in the company actually get their work tasks done. This isn't an evaluation of you. Both successful and unsuccessful cases are equally useful to me. A note-taking assistant is with me: only we see the transcript, and answers go into the report without names. May I turn it on?"</div></div></li><li><span class="sn" style="background:var(--c-light)">2</span><div><div class="st-t">Role and context</div><div class="q">"What do you spend most of your week on?"</div><div class="fu">Which tasks repeat · where you look for information and draft things</div></div></li><li><span class="sn" style="background:var(--c-chat)">3</span><div><div class="st-t">The last work task</div><div class="q">"Think of the last work task that took you noticeable time. What did you need to get?"</div><div class="fu">What means you had · what you chose and why · how you got to the result</div></div></li><li><span class="sn" style="background:var(--c-proj)">4</span><div><div class="st-t">Result and effort</div><div class="q">"What did you end up with, and how much effort did it take?"</div><div class="fu">What you used as is · what you finished yourself · what constraints there were: data, access, security</div></div></li><li><span class="sn" style="background:var(--c-team)">5</span><div><div class="st-t">A successful case</div><div class="q">"Think of a time a similar task went well. What was different then?"</div><div class="fu">Tool · data · preparation</div></div></li><li><span class="sn" style="background:var(--c-work)">6</span><div><div class="st-t">Quitting and switching</div><div class="q">"Have you ever stopped using a tool or switched to another? How did that go?"</div><div class="fu">Which tool · what you switched to · why. If this never happened, skip it</div></div></li><li><span class="sn" style="background:var(--c-none);color:var(--ink)">7</span><div><div class="st-t">Wrap-up</div><div class="q">"What didn't I ask that matters for understanding your work?"</div><div class="fu">Thank them · say the answers go into the shared analysis without names</div></div></li></ol><div class="branch"><span class="bi" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="9" r="2.5"/><path d="M6 8.5v7M8.3 7c4 1 7 0 7.7 0"/></svg></span><div><b>If the person doesn't mention AI</b><span>Don't ask why they don't use it. Ask how they did the task and which options they considered. Ask about AI only if the person named it as a possible option themselves</span></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The last task, result and effort take 13 of 30 minutes; the successful case and quitting or switching take another 9.</div><div class="fg"><span class="fk">In general</span>The conversation is built around the work, not the tool. That shows where AI helps, where the person chose another way, and where no new tool is needed. The successful case shows what already works; quitting and switching show why tools get replaced.</div><div class="fa"><span class="fk">Next step</span>Set a timer: by minute 5, move on to the last work task. If not, cut the context down to one question. Pick the task topic for the person: their tasks show up in <a href="/en/blog/chatgpt-enterprise-usage-report/#projects">Project themes</a>.</div></div></section><section class="chapter" id="focus"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg></span>Staying on topic</h2><div class="rules"><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="3" width="16" height="18" rx="3"/><path d="M10 17V8h3a2.5 2.5 0 0 1 0 5h-3"/></svg></span><b>Parking lot</b><span>Off-topic points go into a separate field; come back to them in the last 2 minutes</span></div><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 7l3-2v14M9 19h7"/></svg></span><b>One question at a time</b><span>No "and also…" in the same sentence</span></div><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/></svg></span><b>Back to the case</b><span>General opinion → "Can you recall a specific time?"</span></div><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/><path d="M5 5l14 14"/></svg></span><b>Don't defend the tool</b><span>Answer criticism only with "What happened next?"</span></div><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M10 9v6M14 9v6"/></svg></span><b>5-second pause</b><span>Stay quiet after an answer: people often add the key point themselves</span></div><div class="rule"><span class="ri"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18h6M10 21h4M12 3a6 6 0 0 0-4 10.5c.7.7 1 1.5 1 2.5h6c0-1 .3-1.8 1-2.5A6 6 0 0 0 12 3z"/><path d="M4 4l16 16"/></svg></span><b>Don't suggest solutions</b><span>No ideas of your own, no names of other products</span></div></div><div class="sublabel" style="margin-top:22px">Situation → what to say</div><div class="tbl"><table><thead><tr><th>Situation</th><th>Host's line</th></tr></thead><tbody><tr><td>Asks for a new feature</td><td>"When did you last need it? What did you do then?"</td></tr><tr><td>Drifts into complaints about processes</td><td>"I'll put that in the parking lot. Back to the report task: what happened after?"</td></tr><tr><td>Answers with "usually" and "always"</td><td>"And how did it go the last time?"</td></tr><tr><td>Asks for the host's opinion</td><td>"I'll share at the end. Right now what matters is how it works for you"</td></tr><tr><td>Block time is up</td><td>"That's important, let's note it. I'll move to the next question"</td></tr></tbody></table></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Five common situations, each with a line that brings the conversation back to the episode.</div><div class="fg"><span class="fk">In general</span>Behind a feature request there is a specific case, and that case is what you need. The request itself is useful later as a hint about where to look for the problem.</div><div class="fa"><span class="fk">Next step</span>Keep the phrase table next to the guide and write every feature request verbatim into a separate table field for off-topic items.</div></div></section><section class="chapter" id="base"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg></span>Logging in Airtable</h2><p class="why">The table keeps everyone in the sample, their conversations and the report data in one place. <b>Decision:</b> whom else to invite so each group has enough interviews, whom to send a follow-up, and which gaps between self-reported and measured use to discuss with the person.</p><div class="pipe" aria-label="Path of a record from call to table"><span class="pn" style="--c:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg><span style="font-weight:700"><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> · <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a></span><small>Transcript</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="pn" style="--c:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg><a href="https://airtable.com" target="_blank" rel="noopener" style="color:inherit;text-decoration:none">Airtable</a><small>Notes field in the person's row</small></span></div><div class="srcs"><a href="https://airtable.com" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg>Airtable<small>Base and forms</small></a><a href="https://tldv.io" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg>tl;dv<small>Call notes and transcripts</small></a><a href="https://www.granola.ai/" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg>Granola<small>Notes without a bot, no audio kept</small></a></div><p class="cap">Voice: the <a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a> or <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a> transcript is copied into the Notes field. Text: the chat log is copied into the same field with the date and time of each message.</p><div class="sublabel" style="margin-top:22px">One table: one row per person</div><div class="atbl"><table><thead><tr><th></th><th><span class="fieldtype">A</span>Name</th><th><span class="fieldtype">≡</span>Notes</th><th><span class="fieldtype">◉</span>Format</th><th><span class="fieldtype">◉</span>Group</th><th><span class="fieldtype">◉</span>Status</th><th class="me"><span class="fieldtype">◉</span>Frequency · self-reported</th><th><span class="fieldtype">◉</span>Frequency · per report</th><th><span class="fieldtype">ƒ</span>≠</th><th><span class="fieldtype">#</span>Tokens · 3 mo</th><th><span class="fieldtype">#</span>$ / 3 mo</th><th><span class="fieldtype">▦</span>Activity</th></tr></thead><tbody><tr><td class="rn">1</td><td class="nm">Hana Sato</td><td class="nt">Host [00:00]: Think back to the last time you…</td><td><span class="at c">voice</span></td><td>code</td><td><span class="at g">Done</span></td><td><span class="at g">weekly</span></td><td><span class="at g">weekly</span></td><td style="text-align:center"><span class="same">=</span></td><td class="r">21.9M</td><td class="r">438</td><td class="r">25.09</td></tr><tr><td class="rn">2</td><td class="nm">Luis Moreno</td><td class="nt">Host [00:00]: Thanks for making the time…</td><td><span class="at c">voice</span></td><td>code</td><td><span class="at g">Done</span></td><td><span class="at c">regularly</span></td><td><span class="at g">weekly</span></td><td style="text-align:center"><span class="dif">≠</span></td><td class="r">12.7M</td><td class="r">396</td><td class="r">24.09</td></tr><tr><td class="rn">3</td><td class="nm">Mira Castellano</td><td class="nt">[26.09 18:40] Host: What result were you expecting…</td><td><span class="at p">text</span></td><td>agent</td><td><span class="at y">Partial</span></td><td><span class="at c">regularly</span></td><td><span class="at c">regularly</span></td><td style="text-align:center"><span class="same">=</span></td><td class="r">3.9M</td><td class="r">97</td><td class="r">26.09</td></tr><tr><td class="rn">4</td><td class="nm">Jonas Keller</td><td class="nt">Host [00:00]: What do you spend most of your…</td><td><span class="at c">voice</span></td><td>research</td><td><span class="at g">Done</span></td><td><span class="at g">weekly</span></td><td><span class="at g">weekly</span></td><td style="text-align:center"><span class="same">=</span></td><td class="r">1.1M</td><td class="r">19</td><td class="r">26.09</td></tr><tr><td class="rn">5</td><td class="nm">Ben Ortiz</td><td class="nt"></td><td></td><td>Codex only</td><td><span class="at c">Awaiting reply</span></td><td></td><td><span class="at p">Codex only</span></td><td style="text-align:center"></td><td class="r">3.2M</td><td class="r">64</td><td class="r">22.09</td></tr><tr><td class="rn">6</td><td class="nm">Pavel Novak</td><td class="nt">[27.09 10:15] Host: Describe the last task…</td><td><span class="at p">text</span></td><td>inactive</td><td><span class="at g">Done</span></td><td><span class="at c">regularly</span></td><td><span class="at rd">doesn't use</span></td><td style="text-align:center"><span class="dif">≠</span></td><td class="r">0</td><td class="r">0</td><td class="r">—</td></tr><tr><td class="rn">7</td><td class="nm">Sara Quinn</td><td class="nt"></td><td></td><td>inactive</td><td><span class="at rd">Declined</span></td><td></td><td><span class="at rd">doesn't use</span></td><td style="text-align:center"></td><td class="r">0</td><td class="r">0</td><td class="r">—</td></tr><tr><td class="rn">8</td><td class="nm">Nadia Rahimi</td><td class="nt">Host [00:00]: What did you do in ChatGPT yesterday…</td><td><span class="at c">voice</span></td><td>other tools</td><td><span class="at g">Done</span></td><td><span class="at y">occasionally</span></td><td><span class="at y">occasionally</span></td><td style="text-align:center"><span class="same">=</span></td><td class="r">0.3M</td><td class="r">6</td><td class="r">20.09</td></tr><tr><td class="rn">9</td><td class="nm">Elif Demir</td><td class="nt"></td><td></td><td>projects</td><td><span class="at n">In progress</span></td><td></td><td><span class="at g">weekly</span></td><td style="text-align:center"></td><td class="r">1.8M</td><td class="r">41</td><td class="r">27.09</td></tr></tbody><tfoot><tr><td colspan="12">16 records · 9 shown</td></tr></tfoot></table></div><p class="cap">ChatGPT fills in the orange field from the conversation in Notes. "Per report", "Tokens", "$" and "Activity" come from the <a href="/en/blog/chatgpt-enterprise-usage-report/">ChatGPT Enterprise usage report</a>. The "≠" field is a formula that compares the two frequencies.</p><div class="sublabel" style="margin-top:22px">Reading the table: what each column gives you</div><div class="tbl"><table><thead><tr><th>Column</th><th>Source</th><th>What it affects</th></tr></thead><tbody><tr><td>Name · Group</td><td><a href="/en/blog/who-to-interview-before-buying-ai-tools/#groups">"Eight groups" sample</a></td><td>which way of getting tasks done the person represents</td></tr><tr><td>Notes</td><td><a href="https://tldv.io/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">tl;dv</a>, <a href="https://www.granola.ai/" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline;text-underline-offset:3px">Granola</a> or chat log</td><td>source for every field; any conclusion is checked against a quote</td></tr><tr><td>Format</td><td>host</td><td>answer depth: a chat has less detail than a call</td></tr><tr><td>Status</td><td>host</td><td>next action: remind, follow up, or replace the person</td></tr><tr><td>Frequency · self-reported</td><td>ChatGPT takes it from the conversation</td><td>how often the person says they use AI</td></tr><tr><td>Frequency · per report</td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#depth">report · adoption depth</a></td><td>how often they use it according to console data</td></tr><tr><td>≠</td><td>Airtable formula: compares the two frequencies</td><td>no match: a question to clarify in the interview, since the report only sees the corporate tool for 3 months</td></tr><tr><td>Tokens · 3 mo</td><td>report · <a href="/en/blog/chatgpt-enterprise-usage-report/#top-spend">top by spend</a></td><td>amount of work in the corporate tool over 3 months, for sampling, not for weighting the answer</td></tr><tr><td>$ · 3 mo</td><td>report · leaderboard</td><td>spend over 3 months, for sampling, not for weighting the answer</td></tr><tr><td>Activity</td><td>report · users export</td><td>date of the last action: long ago means a candidate for the "Tried and quit" group</td></tr></tbody></table></div><div class="sublabel" style="margin-top:22px">How to read the sample rows</div><div class="tbl"><table><thead><tr><th>Row</th><th>Signal</th><th>What to do</th></tr></thead><tbody><tr><td>Hana Sato</td><td>frequencies match · $438 on code · <span class="at g">Done</span></td><td>the highest spend on code: a conversation about her last task shows whether the current tool is enough</td></tr><tr><td>Luis Moreno</td><td><span class="dif">≠</span> says "regularly", actually weekly</td><td>clarify: which tasks he counts as AI work</td></tr><tr><td>Pavel Novak</td><td><span class="dif">≠</span> "regularly" with zero tokens</td><td>clarify: which tools he uses and for which tasks</td></tr><tr><td>Mira Castellano</td><td><span class="at y">Partial</span></td><td>send one follow-up: where in the task they had to finish by hand</td></tr><tr><td>Ben Ortiz</td><td><span class="at c">Awaiting reply</span> · Codex only · $64</td><td>send a reminder: without him the "Codex only" group stays empty</td></tr><tr><td>Sara Quinn</td><td><span class="at rd">Declined</span></td><td>replace by the <a href="/en/blog/who-to-interview-before-buying-ai-tools/#teams">replacement rule</a>: the next candidate of the "Inactive" group</td></tr><tr><td>Elif Demir</td><td><span class="at n">In progress</span> · 7 active projects</td><td>schedule a call; fill in self-reported frequency after the conversation</td></tr></tbody></table></div><div class="sublabel" style="margin-top:22px">Self-reported vs data: what to clarify in the interview</div><div class="vs"><div class="h">Measured in the interview</div><div class="h">Pair in the report</div><div class="h">If they differ, clarify</div><div><b>How often they use it</b></div><div><a href="/en/blog/chatgpt-enterprise-usage-report/#depth">weekly activity</a></div><div>which tools the person uses and for which tasks</div><div><b>Main task</b></div><div><a href="/en/blog/chatgpt-enterprise-usage-report/#main-tool">main tool</a></div><div>which tasks the person counts as AI work</div><div><b>How many tasks it covers</b></div><div><a href="/en/blog/chatgpt-enterprise-usage-report/#projects">number of projects</a></div><div>which projects are alive and for which tasks</div><div><b>What else they use</b></div><div><a href="/en/blog/chatgpt-enterprise-usage-report/#connectors">connectors</a></div><div>what these tools are and for which tasks; record them as a way of working</div><div><b>How much time it saves</b></div><div>no pair</div><div>self-reported only</div></div><p class="cap">Data limits: the report only sees the corporate tool and only for 3 months. Personal accounts and other tools do not show up in it, so a mismatch is a question to clarify, not a conclusion.</p><div class="sublabel" style="margin-top:22px">Statuses of 16 invitees</div><div class="sbar" aria-label="Status breakdown"><div style="flex:9;background:var(--pg);color:var(--pg-i)">Done · 9</div><div style="flex:2;background:var(--py);color:var(--py-i)">2</div><div style="flex:2;background:var(--pc);color:var(--pc-i)">2</div><div style="flex:2;background:var(--pn);color:var(--pn-i)">2</div><div style="flex:1;background:var(--pr);color:var(--pr-i)">1</div></div><div class="legend"><span><i style="background:var(--pg)"></i>Done</span><span><i style="background:var(--py)"></i>Partial</span><span><i style="background:var(--pc)"></i>Awaiting reply</span><span><i style="background:var(--pn)"></i>In progress</span><span><i style="background:var(--pr)"></i>Declined</span></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>9 of 16 invitees gave an interview: the "Done" share is 56%. Pavel Novak's self-reported frequency doesn't match the report.</div><div class="fg"><span class="fk">In general</span>One row per person keeps the report data, format, raw conversation and status together. The statuses show whether you have enough people: the "Done" share among invitees tells you how many to invite so each group gets the needed number of interviews. A gap between self-reported and measured use is a question to clarify: the report only sees the corporate tool for 3 months.</div><div class="fa"><span class="fk">Next step</span>Update the status right after each conversation. Keep the needed number of interviews in each group: with a 56% "Done" share, invite four people for two interviews per group. Send one follow-up to everyone marked Partial.</div></div></section><section class="chapter" id="wording"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg></span>Text: wording</h2><p class="why">In a chat or a questionnaire it is hard to ask again, so a poorly worded question ruins the answer with no chance to fix it. Five common mistakes:</p><div class="pairs"><div class="pr"><span class="tg">leading</span><div class="no">How convenient is the tool for you?</div><div class="yes">Describe the last work task that took you noticeable time.</div></div><div class="pr"><span class="tg">provocative</span><div class="no">Why don't you use the tool if the company pays for it?</div><div class="yes">How did you do your last task of this kind? Which options did you consider?</div></div><div class="pr"><span class="tg">feature request</span><div class="no">What features are you missing?</div><div class="yes">At what point in your last task did you have to finish the work by hand?</div></div><div class="pr"><span class="tg">hypothetical</span><div class="no">Would you use it more if it had an agent?</div><div class="yes">What did you do the last time the result didn't work for you?</div></div><div class="pr"><span class="tg">double-barreled</span><div class="no">What do you do in the tool and how often?</div><div class="yes">What was the last task you did with AI?</div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>All five fixed questions ask about a past episode.</div><div class="fg"><span class="fk">In general</span>Questions about convenience, features and the future collect opinions. A purchase decision rests on what people have already done, so a good question asks about a specific past case.</div><div class="fa"><span class="fk">Next step</span>Reread the chat and questionnaire questions and rewrite every question containing "convenient", "would you like" or "which features" into a question about the last work task.</div></div></section><section class="chapter" id="agent"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg></span>Fill the table with Claude Code</h2><p class="why">The whole table can be handed to an agent: Claude Code or any other MCP-capable agent connects to Airtable and creates rows, pulls report data and analyzes conversations on its own.</p><div class="pipe" aria-label="An agent fills in the table"><span class="pn" style="--c:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg><a href="https://code.claude.com/docs" target="_blank" rel="noopener" style="color:inherit;text-decoration:none">Claude Code</a><small>Or any agent with MCP support</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="pn" style="--c:var(--c-light)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3v5M15 3v5M6 8h12v3a6 6 0 0 1-12 0zM12 17v4"/></svg>Airtable MCP<small>Reads and writes the table</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="pn" style="--c:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg>Airtable<small>All fields and statuses</small></span></div><ul class="todo" style="margin-top:12px"><li><span class="box" aria-hidden="true"></span><div><b>Create rows</b><span class="d">From the list of people selected for interviews: name, group, status</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Pull in report data</b><span class="d">Tokens, $, activity, frequency per report</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Analyze Notes</b><span class="d">With the same prompt as in ChatGPT: fields, difficulties, self-reported frequency, quotes</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Update statuses</b><span class="d">"Partial" (incomplete answer) if the analysis contains "no data"</span></div></li></ul><div class="srcs"><a href="https://support.airtable.com/docs/using-the-airtable-mcp-server" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg>Airtable MCP<small>How to connect</small></a></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The agent creates rows, pulls in the report, analyzes Notes and updates statuses: four steps with no manual entry.</div><div class="fg"><span class="fk">In general</span>Through MCP the agent works with the table directly, leaving the researcher the conversations and checking conclusions against quotes. One analysis prompt for the agent and for ChatGPT keeps rows comparable.</div><div class="fa"><span class="fk">Next step</span>Connect Airtable MCP to Claude Code and start with one command: "Create rows for the people on the list with status In progress".</div></div></section><section class="chapter" id="form"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 8h8M8 12h8M8 16h5"/></svg></span>Questionnaire</h2><p class="why">The questionnaire is written after the interviews, once you know which tasks and difficulties occur. It goes to the whole company to learn how widespread they are. Questions are short, and the answer options come from the interview analysis.</p><ol class="qlist"><li><span class="qn" style="background:var(--c-proj)">1</span><div><b>Which of these tasks do you do at work?</b><span class="bl">choice: tasks from the interviews · other, open field</span><span class="bl">tasks</span></div></li><li><span class="qn" style="background:var(--c-proj)">2</span><div><b>How often do you do these tasks?</b><span class="bl">choice: every day · every week · less often · I don't</span><span class="bl">task frequency</span></div></li><li><span class="qn" style="background:var(--c-proj)">3</span><div><b>Which tools do you use for them?</b><span class="bl">choice: ChatGPT · Claude · Cursor · another AI tool · I don't use AI</span><span class="bl">tools</span></div></li><li><span class="qn" style="background:var(--c-proj)">4</span><div><b>Which difficulties do you run into in these tasks?</b><span class="bl">choice: difficulties from the interviews · I don't run into any · other, open field</span><span class="bl">difficulties</span></div></li><li><span class="qn" style="background:var(--c-proj)">5</span><div><b>How often does this difficulty get in the way?</b><span class="bl">choice: in almost every task · sometimes · rarely</span><span class="bl">difficulty frequency</span></div></li><li><span class="qn" style="background:var(--c-proj)">6</span><div><b>How much does it matter for the result?</b><span class="bl">choice: gets in the way a lot · gets in the way · barely matters</span><span class="bl">impact</span></div></li><li><span class="qn">7</span><div><b>How do you work around this difficulty now?</b><span class="bl">open field · I don't</span><span class="bl">workarounds</span></div></li><li><span class="qn">8</span><div><b>What else matters that the questions missed?</b><span class="bl">open field</span><span class="bl">anything missed</span></div></li></ol><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Eight short questions: six multiple-choice with options from the interviews and two open fields.</div><div class="fg"><span class="fk">In general</span>The interviews show which tasks and difficulties exist; the questionnaire shows how many people face them and how much they get in the way. The options "I don't run into any", "I don't use AI" and the open field catch what the interviews missed.</div><div class="fa"><span class="fk">Next step</span>Collect the answer options from the interview analysis and send the questionnaire to the whole company. Count what share of people face each difficulty, how often, and how much it gets in the way. These shares feed the <a href="/en/blog/chatgpt-enterprise-usage-report/#decision">decision procedure</a> in the report.</div></div></section><section class="chapter" id="after"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18h6M10 21h4M12 3a6 6 0 0 0-4 10.5c.7.7 1 1.5 1 2.5h6c0-1 .3-1.8 1-2.5A6 6 0 0 0 12 3z"/></svg></span>Interview analysis: the analysis prompt and a check against report data</h2><ol class="steps"><li><span class="step-n">1</span><div><div class="step-t">Give the Notes text to ChatGPT</div><div class="step-d">With the same prompt for every interview</div></div></li><li><span class="step-n">2</span><div><div class="step-t">Move ChatGPT's answer into the person's row</div><div class="step-d">Task, context, chosen way, result, effort, constraints, difficulties, self-reported frequency</div></div></li><li><span class="step-n">3</span><div><div class="step-t">Group the table by difficulty</div><div class="step-d">People with the same difficulty end up next to each other: you see how many there are and from which groups</div></div></li><li><span class="step-n">4</span><div><div class="step-t">Check with the questionnaire</div><div class="step-d">Repeats become answer options in the company-wide questionnaire; the team breakdown is compared with <a href="/en/blog/chatgpt-enterprise-usage-report/#uniformity">Uniformity</a></div></div></li></ol><h3 class="pr-h">Prompt for interview analysis</h3><pre class="prompt">Below is a conversation with an employee about their work tasks.&#10;Return strictly by field, only what the person said themselves:&#10;1. Task: the last specific work task&#10;2. Context: for whom and why, what means they had&#10;3. Chosen tool or way, and why&#10;4. Result&#10;5. Effort: time and manual rework&#10;6. Constraints: data, access, security&#10;7. Difficulties: categories from the list {categories from the report's sign table} or "no difficulties"; if none fits, a new category in your own words&#10;8. Self-reported frequency: weekly / regularly / occasionally / doesn't use / unknown&#10;9. 1–2 verbatim quotes&#10;If something is not in the conversation, write "no data" and don't make it up.&#10;&#10;{text from Notes}</pre><div class="gauge" aria-label="What to do with a repeat"><div class="gg"><span>1 person</span><div class="gbar"><i style="width:15%;background:var(--c-none)"></i></div><em>case</em></div><div class="gg"><span>repeats across several</span><div class="gbar"><i style="width:45%;background:var(--c-light)"></i></div><em>check with the questionnaire</em></div><div class="gg"><span>questionnaire confirmed</span><div class="gbar"><i style="width:100%;background:var(--c-work)"></i></div><em>into the decision procedure</em></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A difficulty for one person is a case; a repeat across several is a reason to check with the questionnaire.</div><div class="fg"><span class="fk">In general</span>The analysis keeps the whole task, not just the difficulty: without the context, the chosen way and the effort you cannot tell whether a new tool is needed. A repeat in interviews shows what to check, not how many people face it: only the questionnaire shows that. One prompt for all conversations keeps fields comparable, and "no data" stops ChatGPT from making things up.</div><div class="fa"><span class="fk">Next step</span>Once several analyses have piled up, group the table by difficulty and move repeats into the answer options of the <a href="#form">questionnaire</a>. Record "no difficulties" as a result. Take categories from the report's <a href="/en/blog/chatgpt-enterprise-usage-report/#signs">sign table</a> and add new ones if none fits. The pilot decision follows the <a href="/en/blog/chatgpt-enterprise-usage-report/#decision">procedure</a> in the report.</div></div><div class="sublabel" style="margin-top:22px">Common questions</div><div class="qa"><div><h3>How to analyze an interview with ChatGPT</h3><p>The conversation text from the Notes field goes to ChatGPT with the same prompt for every interview. The answer is copied into the person’s row: task, context, method, result, costs, constraints, difficulties, frequency as stated. Then the table is grouped by difficulty.</p></div><div><h3>Can an agent do the interview analysis</h3><p>Yes. Claude Code or another agent with MCP support connects to Airtable, creates rows, pulls report data and analyzes Notes with the same prompt. The researcher keeps the conversations and checks conclusions against quotes.</p></div><div><h3>How to compare what people say with the data</h3><p>The table has two fields: frequency as stated and frequency by the report, with a mismatch flag next to them. Mismatches are discussed with the person rather than silently corrected.</p></div><div><h3>How to analyze calls and text replies together</h3><p>The text conversation is copied into the same Notes field with the time of each message. Text answers help find cases and themes, but they are not treated as equal to calls.</p></div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/chatgpt-enterprise-usage-report/"><div class="k">Report</div><div class="t">ChatGPT Enterprise usage report</div><div class="d">Who uses it, for which tasks, and which tools to buy next</div></a><a href="/en/blog/who-to-interview-before-buying-ai-tools/"><div class="k">Sample</div><div class="t">Who to interview</div><div class="d">Who to invite for interviews</div></a></div></section><footer>Interview design based on recommendations from <a href="https://t.me/Kseniya_Vasil" target="_blank" rel="noopener">@Kseniya_Vasil</a>. All names, teams and numbers in the examples are fictional.</footer></div>]]></content:encoded></item>
<item><title>ChatGPT Enterprise usage report for a company: who uses it, for what, and which AI tools to buy next</title><link>https://www.urvanov.com/en/blog/chatgpt-enterprise-usage-report/</link><guid>https://www.urvanov.com/en/blog/chatgpt-enterprise-usage-report/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>How to find out how employees use ChatGPT Enterprise: five admin console exports turn into adoption depth, uniformity across teams, main tools, a task map, data checks and an interview shortlist.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-kto-en"><p class="lead-a">ChatGPT Enterprise is a version of ChatGPT for organizations with an admin console that shows who uses the tool and how. This report is built from five console exports and shows adoption depth, uniformity across teams, the nature of tasks and the people to interview. It is used to decide which AI tools to buy, whom to train and which assumptions to test.</p><div class="map" aria-label="Four areas of analysis"><a class="dir" href="#layer1"><div class="dir-h"><span class="n">01</span><i style="background:var(--c-chat)"></i>Big picture</div><div class="viz"><div class="fun"><div style="width:82%;background:var(--d-rare);color:var(--d-rare-t)">82%</div><div style="width:47%;background:var(--d-reg);color:var(--d-reg-t)">47%</div><div style="width:21%;background:var(--d-week);color:var(--d-week-t)">21%</div></div></div><div class="big">21%<small>Use it every week</small></div><div class="dec">Where to invest in training</div></a><a class="dir" href="#layer2"><div class="dir-h"><span class="n">02</span><i style="background:var(--c-work)"></i>Nature of work</div><div class="viz"><svg viewBox="0 0 120 120" width="104" height="104" aria-hidden="true"><circle cx="60" cy="60" r="44" fill="none" stroke="var(--c-work)" stroke-width="18"/><circle cx="60" cy="60" r="44" fill="none" stroke="var(--c-code)" stroke-width="18" stroke-dasharray="193.6 276.5" transform="rotate(-90 60 60)"/></svg></div><div class="big">70%<small>Of connections are Slack and Notion</small></div><div class="dec">Which tool to buy</div></a><a class="dir" href="#layer3"><div class="dir-h"><span class="n">03</span><i style="background:var(--c-code)"></i>Verification</div><div class="viz"><div class="chk"><div class="csv"><span style="background:var(--c-chat)">CHAT</span><span style="background:var(--c-work)">WORK</span><span style="background:var(--c-code)">CODEX</span></div><span class="eq">=</span><span class="ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span></div></div><div class="big">±2%<small>Export reconciliation tolerance</small></div><div class="dec">Can the numbers be trusted</div></a><a class="dir" href="#layer4"><div class="dir-h"><span class="n">04</span><i style="background:var(--c-proj)"></i>People selection</div><div class="viz"><div class="dots" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on"></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div><div class="big">16<small>Of 340 in the example — for interviews</small></div><div class="dec">Who to talk to before buying</div></a></div><section class="chapter" id="why"><h2>Which decisions the report helps make</h2><p class="lead"><b>Business task:</b> find out for which work tasks the current set of AI tools falls short and which solutions are worth testing before buying. The decision is made by the owner of the AI tools budget together with the leads of the teams where the pilot runs. Data access and security are approved by the information security team. The decision criteria are the signs in the table below.</p><p>That the current set is suboptimal somewhere is an assumption: the report and the interviews test it. "Suboptimal" breaks down into testable signs. The conclusion "no new tool is needed" is also a result.</p><div class="tbl" id="signs"><table><thead><tr><th>Sign</th><th>How it shows</th><th>Interview category</th><th>Where the report shows it</th></tr></thead><tbody><tr><td>Result quality</td><td>answers are inaccurate or made up</td><td><span class="tag no">hallucinations</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#connectors">Connectors</a></td></tr><tr><td>Time and manual rework</td><td>a lot of back-and-forth, the result is finished by hand</td><td><span class="tag no">prompt</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#depth">Depth</a>, <a href="/en/blog/chatgpt-enterprise-usage-report/#main-tool">Main tool</a></td></tr><tr><td>Reproducibility</td><td>a different result on the same task every time</td><td><span class="tag no">reproducibility</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#skills">Skills</a>, <a href="/en/blog/chatgpt-enterprise-usage-report/#projects">Project themes</a></td></tr><tr><td>Scale</td><td>a working scenario does not transfer to another team</td><td><span class="tag no">scale</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#uniformity">Uniformity</a></td></tr><tr><td>Data access</td><td>the needed system is not connected</td><td><span class="tag no">data access</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#connectors">Connectors</a></td></tr><tr><td>Cost</td><td>expensive per unit of result</td><td><span class="tag no">cost</span></td><td><a href="/en/blog/chatgpt-enterprise-usage-report/#top-spend">Top by spend</a></td></tr></tbody></table></div><p class="cap">Data limits: the report only sees the corporate tool and only for the export period, 3 months. Personal accounts and other tools do not show up in it.</p><h3 id="decision" style="margin-top:22px">How answers turn into a purchase decision</h3><p class="why">The report shows where to look, and the purchase decision is made only after these five steps, so the money goes to a task many people have and nothing covers today.</p><ol class="steps"><li><span class="step-n">1</span><div><div class="step-t">Interviews</div><div class="step-d">Which tasks and difficulties exist and how people work around them now</div></div></li><li><span class="step-n">2</span><div><div class="step-t">Company-wide questionnaire</div><div class="step-d">How many people face a difficulty, how often, and how much it gets in the way</div></div></li><li><span class="step-n">3</span><div><div class="step-t">Compare</div><div class="step-d">Task scale, severity of consequences, workarounds, cost of the solution</div></div></li><li><span class="step-n">4</span><div><div class="step-t">Test tools</div><div class="step-d">Promising options on real tasks together with employees</div></div></li><li><span class="step-n">5</span><div><div class="step-t">Decision</div><div class="step-d">The budget owner decides by the six <a href="#signs">signs above</a>: quality, time and rework, reproducibility, scale, data access, cost; "no new tool is needed" is a valid outcome</div></div></li></ol><div class="io"><div><div class="k">Input</div><div class="v">Console exports: messages, spend, projects, and connectors for each person</div></div><div><div class="k">What the report does</div><div class="v">Turns exports into segments, team maturity, and specific people as material for a decision</div></div><div><div class="k">Decisions at the output</div><div class="v">Which tool to pilot, for which team, who to talk to before buying, and where budget is not needed</div></div></div></section><section class="chapter" id="order"><h2>Workflow</h2><p>Five steps from export to a finished list of people.</p><ol class="steps"><li><span class="step-n">1</span><div><div class="step-t">Export the data</div><div class="step-d">Five console sections, details in "Where to get the data"</div></div></li><li><span class="step-n">2</span><div><div class="step-t">Build the big picture</div><div class="step-d">Adoption depth, uniformity across teams, main tool, segments</div></div></li><li><span class="step-n">3</span><div><div class="step-t">Map the nature of work</div><div class="step-d">Which tasks people solve, with which built-in tools, and with which integrations</div></div></li><li><span class="step-n">4</span><div><div class="step-t">Check against raw data</div><div class="step-d">Verify each summary against the source export</div></div></li><li><span class="step-n">5</span><div><div class="step-t">Select people and draw conclusions</div><div class="step-d">An interview list and the questions to test in them</div><div class="step-l"><a href="/en/blog/who-to-interview-before-buying-ai-tools/">Who to interview <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a><a href="/en/blog/ai-interviews-without-leading-questions/">How to run the interviews <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a></div></div></li></ol></section><section class="chapter" id="data"><h2>What a ChatGPT Enterprise admin sees: where to get the data</h2><p>Everything is built from five sections of a single <a href="https://openai.com/chatgpt/enterprise/" target="_blank" rel="noopener">ChatGPT Enterprise</a> admin console. Hover over <b>i</b> to see exactly what each section contains.</p><h3 class="pr-h">How to export data from the ChatGPT Enterprise console: by hand and with the Claude in Chrome browser agent</h3><div class="howto"><b>How to export.</b> The console does have APIs, but they cover only part of the data: <a href="https://learn.chatgpt.com/docs/enterprise/analytics-api" target="_blank" rel="noopener">Codex analytics</a>, credit costs, and conversation logs for compliance. The users, projects and skills exports and the per-product leaderboard are easier to collect in the interface. Exporting is a good job for <a href="https://claude.com/claude-in-chrome" target="_blank" rel="noopener">Claude in Chrome</a>: it opens the right section, sets the filter, clicks export, and saves the CSV. Every step is visible on screen, so a wrong filter or section is caught immediately, before the numbers reach the report.<div class="howto-w"><span class="howto-wi"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 3v6c0 4.5-3.4 8.3-8 9-4.6-.7-8-4.5-8-9V6z"/><path d="M12 8v5M12 16h.01"/></svg></span><span><b>Access.</b> The console API is not always available: company security policies often restrict admin API keys. In that case, export every section through the interface.</span></div></div><div class="sources"><div class="src"><div class="src-ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 19v-1a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v1"/><circle cx="9" cy="7" r="3.5"/><path d="M22 19v-1a4 4 0 0 0-3-3.9"/><path d="M16 3.3a3.5 3.5 0 0 1 0 6.9"/></svg></div><div><div class="src-name"><a href="https://chatgpt.com/admin/usage/users" target="_blank" rel="noopener">Users</a></div><div class="src-path">chatgpt.com/admin/usage/users</div><div class="src-what">Messages, activity dates, and built-in tools for each person</div></div><span class="tip" tabindex="0" aria-label="What is inside the Users section">i<span class="tip-body" role="tooltip"><span class="pl">What's inside</span>CSV export for a period of up to 12 months. Fields: messages, tool_messages, gpt_messages, project_messages, department, groups, seat_type, last_day_active. The console itself marks "power users" with a badge.</span></span></div><div class="src"><div class="src-ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0z"/><path d="M17 5h3v2a3 3 0 0 1-3 3M7 5H4v2a3 3 0 0 0 3 3"/></svg></div><div><div class="src-name"><a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a></div><div class="src-path">admin.openai.com → Analytics → Leaderboard</div><div class="src-what">Spend, tokens, and lines of code for each person, separately for the Chat, Work, and Codex products</div></div><span class="tip" tabindex="0" aria-label="What is inside the Leaderboard">i<span class="tip-body" role="tooltip"><span class="pl">What's inside</span>Export button next to the heading → "User ranking", CSV or JSON. Fields: Name, Email, Credits, Estimated costs, Tokens, Lines of code. The "Product" filter changes what the export contains. History covers about 120 days.</span></span></div><div class="src"><div class="src-ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></div><div><div class="src-name"><a href="https://chatgpt.com/admin/usage/projects" target="_blank" rel="noopener">Projects</a></div><div class="src-path">chatgpt.com/admin/usage/projects</div><div class="src-what">Who created a project, how many messages it has, and whether it is active</div></div><span class="tip" tabindex="0" aria-label="What is inside the Projects section">i<span class="tip-body" role="tooltip"><span class="pl">What's inside</span>Fields: project_name, project_creator_email, messages_workspace, unique_messagers_workspace, is_active. Some names come through as [content redacted]: the console hides them on its own.</span></span></div><div class="src"><div class="src-ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 2v5M15 2v5M6 7h12v4a6 6 0 0 1-12 0z"/><path d="M12 17v5"/></svg></div><div><div class="src-name"><a href="https://chatgpt.com/admin/usage" target="_blank" rel="noopener">Overview: connectors and skills</a></div><div class="src-path">chatgpt.com/admin/usage</div><div class="src-what">Which apps people connect the assistant to and which skills they use</div></div><span class="tip" tabindex="0" aria-label="What is inside the Overview section">i<span class="tip-body" role="tooltip"><span class="pl">What's inside</span>The "App interactions" and "Skills" blocks: the number of calls to each connector and skill over the selected period.</span></span></div><div class="src"><div class="src-ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M7 15l4-4 3 3 5-6"/></svg></div><div><div class="src-name"><a href="https://admin.openai.com" target="_blank" rel="noopener">Analytics: tasks</a></div><div class="src-path">admin.openai.com → Analytics → Tasks</div><div class="src-what">The console's own task classification: code or knowledge work (everything except code)</div></div><span class="tip" tabindex="0" aria-label="What is inside the Tasks tab">i<span class="tip-body" role="tooltip"><span class="pl">What's inside</span>Share of code and knowledge work, top tasks by credits. An OpenAI model labels tasks on a sample of about 10% of requests over 30 days.</span></span></div></div></section><section class="chapter" id="layer1"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></span>Big picture</h2><p>The next four sections are the report itself, each with its goal. <b>Goal:</b> show which groups of people exist in the company and how large they are.</p><div class="block"><h3 id="depth">Adoption depth</h3><div class="dp"><svg class="dp-v" style="color:var(--d-rare)" viewBox="0 0 200 72" role="img" aria-label="Used at least once: one week out of eight" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="60" cy="18" r="6"/><path d="M50 38c0-7 4.5-11 10-11s10 4 10 11"/></g><path d="M80 24H120" stroke-dasharray="4 5"/><rect x="129" y="13" width="22" height="22" rx="6"/><path d="M140 13v-4"/><circle cx="136" cy="23" r="1.6" fill="currentColor"/><circle cx="144" cy="23" r="1.6" fill="currentColor"/><path d="M136 29h8"/><rect x="24" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="44" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="64" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="84" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="104" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="124" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="144" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="164" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/></svg><svg class="dp-v" style="color:var(--d-reg)" viewBox="0 0 200 72" role="img" aria-label="Regularly: several weeks out of eight" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="60" cy="18" r="6"/><path d="M50 38c0-7 4.5-11 10-11s10 4 10 11"/></g><path d="M80 24H120" stroke-dasharray="4 5"/><rect x="129" y="13" width="22" height="22" rx="6"/><path d="M140 13v-4"/><circle cx="136" cy="23" r="1.6" fill="currentColor"/><circle cx="144" cy="23" r="1.6" fill="currentColor"/><path d="M136 29h8"/><rect x="24" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="44" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="64" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="84" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="104" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/><rect x="124" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="144" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="164" y="52" width="14" height="14" rx="3" stroke-opacity=".35"/></svg><svg class="dp-v" style="color:var(--d-week)" viewBox="0 0 200 72" role="img" aria-label="Every week: all eight weeks" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="60" cy="18" r="6"/><path d="M50 38c0-7 4.5-11 10-11s10 4 10 11"/></g><path d="M80 24H120" /><rect x="129" y="13" width="22" height="22" rx="6"/><path d="M140 13v-4"/><circle cx="136" cy="23" r="1.6" fill="currentColor"/><circle cx="144" cy="23" r="1.6" fill="currentColor"/><path d="M136 29h8"/><rect x="24" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="44" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="64" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="84" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="104" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="124" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="144" y="52" width="14" height="14" rx="3" fill="currentColor"/><rect x="164" y="52" width="14" height="14" rx="3" fill="currentColor"/></svg></div><p class="why">Adoption depth shows how deeply the tool has entered the company's work: how many people have used it at least once, regularly, and every week. Those who never write in chat and work only through Codex are shown separately. <b>Decision:</b> which group to invest training in and whether to buy more licenses now.</p><div class="stack"><div class="seg" style="width:20.9%;background:var(--d-week);color:var(--d-week-t)">71</div><div class="seg" style="width:25.9%;background:var(--d-reg);color:var(--d-reg-t)">88</div><div class="seg" style="width:28.5%;background:var(--d-rare);color:var(--d-rare-t)">97</div><div class="seg" style="width:6.8%;background:var(--d-api);color:var(--d-api-t)">23</div><div class="seg" style="width:17.9%;background:var(--d-none);color:var(--d-none-t)">61</div></div><div class="legend"><span><i style="background:var(--d-week)"></i>every week</span><span><i style="background:var(--d-reg)"></i>regularly</span><span><i style="background:var(--d-rare)"></i>occasionally</span><span><i style="background:var(--d-api)"></i>Codex only</span><span><i style="background:var(--d-none)"></i>fully inactive</span></div><p class="cap">340 people</p><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage/users" target="_blank" rel="noopener">Users</a> · <a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a> for those who work only through Codex</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>82% of people have tried the tool, 47% use it in their work, and for 21% it has become a weekly habit. The room to grow depth is the 97 people in the "occasionally" group.</div><div class="fg"><span class="fk">In general</span>The gap between "tried it" and "use it every week" shows how many people stopped after the first attempts. The benchmark for mass adoption is 50–70% of employees using it in daily work. Until adoption reaches that benchmark, more licenses will not drive growth: something other than access is holding people back.</div><div class="fa"><span class="fk">Next step</span>Put training into the largest group between "tried it" and "every week": it gives the fastest growth in regular use. Recount the breakdown after the training to see where people moved.</div></div><div class="note"><span class="note-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 21V4h11l-1.5 4L16 12H5"/></svg></span><div><b>Important.</b> Pick 5–10 people from the "occasionally" group, find out in interviews how they get their tasks done now, and run a review of real work cases with them. Recount the weekly share after the review. How to ask without suggesting the answer is covered in <a href="/en/blog/ai-interviews-without-leading-questions/">"How to interview people about their AI use"</a>.</div></div></div><div class="block"><h3 id="uniformity">Uniformity</h3><div class="dp" style="grid-template-columns:1fr"><svg class="dp-v" style="color:var(--accent);max-height:120px" viewBox="0 0 310 72" role="img" aria-label="Teams fall into three groups: strong A and B, middle C, lagging D and E; scenarios move from the strong to the lagging" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"><rect x="6" y="8" width="94" height="38" rx="5" stroke="var(--line-2)"/><circle cx="15.0" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="23.4" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="31.8" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="40.2" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="48.6" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="57.0" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="65.4" cy="20" r="3" fill="var(--d-week)" stroke="none"/><circle cx="73.8" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="82.2" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="90.6" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="15.0" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="23.4" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="31.8" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="40.2" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="48.6" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="57.0" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="65.4" cy="34" r="3" fill="var(--d-week)" stroke="none"/><circle cx="73.8" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="82.2" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="90.6" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><rect x="108" y="8" width="94" height="24" rx="5" stroke="var(--line-2)"/><circle cx="117.0" cy="20" r="3" fill="var(--d-reg)" stroke="none"/><circle cx="125.4" cy="20" r="3" fill="var(--d-reg)" stroke="none"/><circle cx="133.8" cy="20" r="3" fill="var(--d-reg)" stroke="none"/><circle cx="142.2" cy="20" r="3" fill="var(--d-reg)" stroke="none"/><circle cx="150.6" cy="20" r="3" fill="var(--d-reg)" stroke="none"/><circle cx="159.0" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="167.4" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="175.8" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="184.2" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="192.6" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><rect x="210" y="8" width="94" height="38" rx="5" stroke="var(--line-2)"/><circle cx="219.0" cy="20" r="3" fill="var(--d-rare)" stroke="none"/><circle cx="227.4" cy="20" r="3" fill="var(--d-rare)" stroke="none"/><circle cx="235.8" cy="20" r="3" fill="var(--d-rare)" stroke="none"/><circle cx="244.2" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="252.6" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="261.0" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="269.4" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="277.8" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="286.2" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="294.6" cy="20" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="219.0" cy="34" r="3" fill="var(--d-rare)" stroke="none"/><circle cx="227.4" cy="34" r="3" fill="var(--d-rare)" stroke="none"/><circle cx="235.8" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="244.2" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="252.6" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="261.0" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="269.4" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="277.8" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="286.2" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><circle cx="294.6" cy="34" r="3" stroke="var(--line-2)" stroke-width="1.2"/><path d="M53 46C90 76 216 76 257 46" stroke="currentColor"/><path d="M251 44l6 2-2 6" stroke="currentColor"/></svg></div><p class="why">Uniformity shows how evenly the tool has entered different teams: what share of each team uses it regularly and how many messages one person writes on average. <b>Decision:</b> which team to take working scenarios from and which team to bring them to first.</p><div class="tbl"><table><thead><tr><th>Team</th><th>Regular users</th><th class="r">%</th><th class="r">Msgs per person</th></tr></thead><tbody><tr class="grp"><td colspan="4"><i style="background:var(--d-week)"></i>Strong · source of scenarios</td></tr><tr><td>Team A</td><td><div class="dbar"><span style="width:74%"></span></div></td><td class="r">74%</td><td class="r">1,120</td></tr><tr><td>Team B</td><td><div class="dbar"><span style="width:66%"></span></div></td><td class="r">66%</td><td class="r">870</td></tr><tr class="grp"><td colspan="4"><i style="background:var(--d-reg)"></i>Middle</td></tr><tr><td>Team C</td><td><div class="dbar"><span style="width:51%"></span></div></td><td class="r">51%</td><td class="r">720</td></tr><tr class="grp"><td colspan="4"><i style="background:var(--d-rare)"></i>Lagging · where to bring scenarios</td></tr><tr><td>Team D</td><td><div class="dbar"><span style="width:34%"></span></div></td><td class="r">34%</td><td class="r">530</td></tr><tr><td>Team E</td><td><div class="dbar"><span style="width:18%"></span></div></td><td class="r">18%</td><td class="r">290</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage/users" target="_blank" rel="noopener">Users</a> · department and groups fields</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>In Team A, 74% of people use the tool regularly; in Team E, 18%: a spread of 56 percentage points.</div><div class="fg"><span class="fk">In general</span>A large spread between teams means working scenarios already exist but live in one or two teams: moving them is cheaper than buying something new. A uniformly low share across all teams points to a shared barrier: access, training, or unsuitable tasks. A uniformly high share means the tool has taken root and you can move to the next step. A team with barriers is not ready for a new tool yet.</div><div class="fa"><span class="fk">Next step</span>With a large spread, run a meetup: the strongest team shows three of its scenarios to the two weakest. Before the meetup, run 2–3 interviews about barriers in the weakest team. Recount the spread after the meetup: it should shrink.</div></div></div><div class="block"><h3 id="main-tool">Main tool</h3><p class="why">Which of the three tools takes more than half of a person's spend over three months. The tool type shows how the person works with AI.</p><div class="tt"><div class="tt-c" style="--c:var(--c-chat)"><div class="tt-h"><span class="tt-n">1</span><a href="https://openai.com/chatgpt/enterprise/" target="_blank" rel="noopener">Chat</a></div><svg class="tt-v" viewBox="0 0 200 58" role="img" aria-label="A person goes back and forth with the chat many times, the result is unclear and may be made up" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="16" cy="24" r="6"/><path d="M6 44c0-7 4.5-11 10-11s10 4 10 11"/></g><path d="M32 18H92M87 14l5 4-5 4"/><path d="M92 30H32M37 26l-5 4--5 4"/><path d="M32 42H92M87 38l5 4-5 4"/><rect x="101" y="21" width="22" height="22" rx="6"/><path d="M112 21v-4"/><circle cx="108" cy="31" r="1.6" fill="currentColor"/><circle cx="116" cy="31" r="1.6" fill="currentColor"/><path d="M108 37h8"/><path d="M128 32H146M141 28l5 4-5 4"/><g><path d="M154 42a8 8 0 0 1 1-16 11 11 0 0 1 21-3 8 8 0 0 1 4 19z"/><path d="M163.5 28a3.5 3.5 0 1 1 5 3.2c-1 .5-1.5 1.2-1.5 2.3M167 37.5h.01"/></g></svg><div class="tt-ps" role="list" aria-label="Problems"><span role="listitem" class="tt-pc on" title="many messages per task; "I have to re-ask many times"" aria-label="Prompt: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Prompt</span><span role="listitem" class="tt-pc on" title="few app connections; "I have to double-check everything"" aria-label="Hallucinations: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Hallucinations</span><span role="listitem" class="tt-pc on" title="the same tasks without projects or skills; "it comes out different every time"" aria-label="Reproducibility: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Reproducibility</span><span role="listitem" class="tt-pc on" title="skills are built in one team only; "it does not work for the team next door"" aria-label="Scale: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Scale</span></div></div><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><div class="tt-c" style="--c:var(--c-work)"><div class="tt-h"><span class="tt-n">2</span><a href="https://help.openai.com/en/articles/20001275-chatgpt-work-and-codex" target="_blank" rel="noopener">Work</a></div><svg class="tt-v" viewBox="0 0 200 58" role="img" aria-label="A person sets one goal, the agent takes data from apps, but the documents differ each time" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="14" cy="24" r="6"/><path d="M4 44c0-7 4.5-11 10-11s10 4 10 11"/></g><path d="M28 32H58M53 28l5 4-5 4"/><rect x="69" y="21" width="22" height="22" rx="6"/><path d="M80 21v-4"/><circle cx="76" cy="31" r="1.6" fill="currentColor"/><circle cx="84" cy="31" r="1.6" fill="currentColor"/><path d="M76 37h8"/><rect x="61" y="1" width="9" height="8" rx="2"/><rect x="75.5" y="1" width="9" height="8" rx="2"/><rect x="90" y="1" width="9" height="8" rx="2"/><path d="M65.5 9l8.5 12M80 9v12M94.5 9l-8.5 12" stroke-dasharray="2 3"/><path d="M96 32H116M111 28l5 4-5 4"/><path d="M120 16h14l6 6v24h-20z"/><path d="M134 16v6h6M124 30h12M124 35h12M124 40h8"/><path d="M146 29h8M146 35h8M152 25l-4 14"/><path d="M160 16h14l6 6v24h-20z"/><path d="M174 16v6h6M164 28h7M164 33h12M164 38h5M164 42h10"/></svg><div class="tt-ps" role="list" aria-label="Problems"><span role="listitem" class="tt-pc" title="many messages per task; "I have to re-ask many times"" aria-label="Prompt: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Prompt</span><span role="listitem" class="tt-pc" title="few app connections; "I have to double-check everything"" aria-label="Hallucinations: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Hallucinations</span><span role="listitem" class="tt-pc on" title="the same tasks without projects or skills; "it comes out different every time"" aria-label="Reproducibility: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Reproducibility</span><span role="listitem" class="tt-pc on" title="skills are built in one team only; "it does not work for the team next door"" aria-label="Scale: present"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M7 7l10 10M17 7L7 17"/></svg>Scale</span></div></div><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><div class="tt-c" style="--c:var(--c-code)"><div class="tt-h"><span class="tt-n">3</span><a href="https://openai.com/codex/" target="_blank" rel="noopener">Codex</a></div><svg class="tt-v" viewBox="0 0 200 58" role="img" aria-label="Following the spec and rules, the agent delivers the same result for several teams" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="14" width="24" height="32" rx="3"/><path d="M8 22l2 2 3-3M17 23h7M8 30l2 2 3-3M17 31h7M8 38l2 2 3-3M17 39h7"/><path d="M32 32H52M47 28l5 4-5 4"/><rect x="59" y="21" width="22" height="22" rx="6"/><path d="M70 21v-4"/><circle cx="66" cy="31" r="1.6" fill="currentColor"/><circle cx="74" cy="31" r="1.6" fill="currentColor"/><path d="M66 37h8"/><path d="M86 32C108 32 116 12 144 12M86 32H144M86 32C108 32 116 52 144 52"/><rect x="148" y="6" width="30" height="12" rx="2"/><path d="M159 9l-3 3 3 3M167 9l3 3-3 3"/><rect x="148" y="26" width="30" height="12" rx="2"/><path d="M159 29l-3 3 3 3M167 29l3 3-3 3"/><rect x="148" y="46" width="30" height="12" rx="2"/><path d="M159 49l-3 3 3 3M167 49l3 3-3 3"/></svg><div class="tt-ps" role="list" aria-label="Problems"><span role="listitem" class="tt-pc" title="many messages per task; "I have to re-ask many times"" aria-label="Prompt: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Prompt</span><span role="listitem" class="tt-pc" title="few app connections; "I have to double-check everything"" aria-label="Hallucinations: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Hallucinations</span><span role="listitem" class="tt-pc" title="the same tasks without projects or skills; "it comes out different every time"" aria-label="Reproducibility: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Reproducibility</span><span role="listitem" class="tt-pc" title="skills are built in one team only; "it does not work for the team next door"" aria-label="Scale: removed"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Scale</span></div></div></div><div class="stack"><div class="seg" style="width:48.2%;background:var(--c-chat)">164 · Chat</div><div class="seg" style="width:13.8%;background:var(--c-work)">47 · Work</div><div class="seg" style="width:11.2%;background:var(--c-code)">38 · Codex</div><div class="seg dark" style="width:26.8%;background:var(--c-none)">91 · no spend</div></div><p class="cap">340 people, 3-month window</p><p class="cap src-cap">Source: <a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a> · three exports: "Product" filter = Chat, Work, Codex</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Chat is the main product for 164 of 340 people, Codex for 38, Work for 47.</div><div class="fg"><span class="fk">In general</span>The main tool shows the type of work: a conversation, a task handed to an agent, or code. It determines what the person needs next and which pilot to put them in. Group size sets pilot size: a wide pilot for a common scenario, a narrow one for a rare scenario.</div><div class="fa"><span class="fk">Next step</span>The decision is to move each group to the next step. For the Chat group: Work with connectors and MCP to work data, which removes prompting and hallucinations. For the Work group: specs, harness setup and shared skills, which make the result reproducible and transferable to other teams.</div></div></div><div class="block"><h3 id="top-spend">Top by spend</h3><div class="dp"><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 200 72" role="img" aria-label="Most of the spend comes from a few people" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="22" y="12" width="10" height="52" rx="2" fill="currentColor"/><rect x="38" y="18" width="10" height="46" rx="2" fill="currentColor"/><rect x="54" y="50" width="10" height="14" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="70" y="53" width="10" height="11" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="86" y="55" width="10" height="9" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="102" y="56" width="10" height="8" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="118" y="57" width="10" height="7" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="134" y="58" width="10" height="6" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="150" y="59" width="10" height="5" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><rect x="166" y="60" width="10" height="4" rx="2" stroke="var(--line-2)" fill="var(--line-2)"/><path d="M16 64h170" stroke="var(--line-2)"/></svg><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 200 72" role="img" aria-label="An experienced user shares scenarios with several colleagues" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="currentColor"><circle cx="40" cy="24" r="8"/><path d="M27.2 49.6c0-8.8 6.0-14.4 12.8-14.4s12.8 5.6 12.8 14.4"/></g><path d="M40 8l2 4 4 .5-3 3 .8 4-3.8-2-3.8 2 .8-4-3-3 4-.5z" fill="currentColor" stroke="none" transform="translate(0,-6) scale(1)"/><path d="M62 36C92 36 100 14 128 14M62 36H128M62 36C92 36 100 58 128 58"/><g stroke="var(--ink-2)"><circle cx="150" cy="7" r="4"/><path d="M143.6 19.8c0-4.4 3.0-7.2 6.4-7.2s6.4 2.8 6.4 7.2"/></g><g stroke="var(--ink-2)"><circle cx="150" cy="29" r="4"/><path d="M143.6 41.8c0-4.4 3.0-7.2 6.4-7.2s6.4 2.8 6.4 7.2"/></g><g stroke="var(--ink-2)"><circle cx="150" cy="51" r="4"/><path d="M143.6 63.8c0-4.4 3.0-7.2 6.4-7.2s6.4 2.8 6.4 7.2"/></g></svg><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 200 72" role="img" aria-label="The experiment cut the time per task, and everyone adopted the practice" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="14" y="20" width="84" height="10" rx="3" fill="var(--line-2)" stroke="none"/><rect x="14" y="42" width="34" height="10" rx="3" fill="currentColor" stroke="none"/><path d="M108 36h20M123 31l5 5-5 5"/><g stroke="var(--ink-2)"><circle cx="146" cy="34" r="5"/><path d="M138.0 50.0c0-5.5 3.8-9.0 8.0-9.0s8.0 3.5 8.0 9.0"/></g><path d="M142 17l3 3 5-6"/><g stroke="var(--ink-2)"><circle cx="166" cy="34" r="5"/><path d="M158.0 50.0c0-5.5 3.8-9.0 8.0-9.0s8.0 3.5 8.0 9.0"/></g><path d="M162 17l3 3 5-6"/><g stroke="var(--ink-2)"><circle cx="186" cy="34" r="5"/><path d="M178.0 50.0c0-5.5 3.8-9.0 8.0-9.0s8.0 3.5 8.0 9.0"/></g><path d="M182 17l3 3 5-6"/></svg></div><p class="why">The top list ranks people by the amount spent on a specific product, for example Codex. This way the list includes someone who spends a lot on Codex even if most of their spend goes to Chat.</p><div class="tbl"><table><thead><tr><th>Person</th><th>Team</th><th class="r">$ on code / 3 mo</th><th class="r">Tokens / 3 mo</th><th class="r">Tokens per $</th></tr></thead><tbody><tr><td>Hana Sato</td><td>Team C</td><td class="r">438.20</td><td class="r">21.9M</td><td class="r">50K</td></tr><tr><td>Luis Moreno</td><td>Team A</td><td class="r">395.60</td><td class="r">12.7M</td><td class="r">32K</td></tr><tr><td>Ada Kowalski</td><td>Team D</td><td class="r">84.30</td><td class="r">4.3M</td><td class="r">51K</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a> · one export per product</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Hana Sato and Luis Moreno spend about five times more on code than the third person on the list. With similar spend, Hana gets one and a half times more tokens per dollar than Luis.</div><div class="fg"><span class="fk">In general</span>Top users are change agents: they find working scenarios first, and their experience affects whether a specialized tool pays off. Next to them are more cautious colleagues who need more time and a live example on their own tasks. Ranking by share of spend hides the change agents, so look at absolute spend.</div><div class="fa"><span class="fk">Next step</span>Involve top users as mentors: let them show their scenarios to colleagues who are just starting, on those colleagues' tasks. Invite cautious colleagues through examples and results, without mandates. Offer the top two or three an experiment in a specialized tool with a before-and-after report.</div></div><div class="note"><span class="note-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></svg></span><div>The leaderboard has both spend and tokens. Compare the tokens-to-spend ratio within one group: one product and similar tasks. Whoever gets noticeably more tokens per dollar usually picks models and modes better. These are the most advanced and efficient users, and they are the first to invite as mentors. Introduce them to colleagues from the same group whose ratio is lower: working through one task together often gives more than a general training. Pairs from different teams bring cross-pollination: good techniques move between teams.</div></div><div class="note"><span class="note-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8v.5"/></svg></span><div>During rollout, top users can spend an order of magnitude more than everyone else. It is better not to introduce limits at this stage: they easily demotivate the people who adopt the tool first. Instead of limits, agree on experiments and a results report. Limits make sense later, once practices are proven and the normal cost of a scenario is clear.</div></div></div><div class="block"><h3 id="segments">Behavioral segments</h3><div class="cf" role="img" aria-label="segment → interview → problem → tool"><span class="cf-s"><svg viewBox="0 0 64 48" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="24" cy="24" r="16"/><circle cx="40" cy="24" r="16"/><circle cx="17" cy="22" r="2.5" fill="currentColor"/><circle cx="32" cy="18" r="2.5" fill="currentColor"/><circle cx="32" cy="30" r="2.5" fill="currentColor"/><circle cx="47" cy="24" r="2.5" fill="currentColor"/></svg><small>segment</small></span><span class="cf-a" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="cf-s"><svg viewBox="0 0 64 48" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><g stroke="var(--ink-2)"><circle cx="14" cy="24" r="5"/><path d="M6.0 40.0c0-5.5 3.8-9.0 8.0-9.0s8.0 3.5 8.0 9.0"/></g><g stroke="var(--ink-2)"><circle cx="50" cy="24" r="5"/><path d="M42.0 40.0c0-5.5 3.8-9.0 8.0-9.0s8.0 3.5 8.0 9.0"/></g><path d="M20 6h16v10h-9l-4 4v-4h-3z"/><path d="M44 12H30v9h3v4l4-4h7z" stroke-dasharray="0"/></svg><small>interview</small></span><span class="cf-a" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="cf-s"><svg viewBox="0 0 64 48" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><g stroke="var(--warn)"><path d="M32 8l20 34H12z"/><path d="M32 21v10M32 36h.01"/></g></svg><small>problem</small></span><span class="cf-a" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="cf-s"><svg viewBox="0 0 64 48" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 12h14a4 4 0 1 1 8 0h14v12a4 4 0 1 0 0 8v10H10z" stroke="var(--line-2)" stroke-dasharray="3 3"/><path d="M14 16h10a4 4 0 1 1 8 0h10v9a4 4 0 1 0 0 8v5H14z" fill="color-mix(in srgb, currentColor 22%, transparent)"/></svg><small>tool</small></span></div><p class="why">Groups by behavior intensity built from several exports: how much a person writes, spends and what they do.</p><div class="tbl"><table><thead><tr><th>Segment</th><th class="r">People</th><th>Details</th></tr></thead><tbody><tr><td>Write code in any product</td><td class="r">44</td><td>19 of them outside technical teams</td></tr><tr><td>Intensive research in chat</td><td class="r">58</td><td>1,900+ messages on average</td></tr><tr><td>Agentic tasks</td><td class="r">33</td><td>multi-step scenarios, connectors</td></tr><tr><td>Image generation</td><td class="r">21</td><td>two thirds from one team</td></tr><tr><td>Fully inactive</td><td class="r">61</td><td>0 messages, $0 over the whole period</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage/users" target="_blank" rel="noopener">Users</a> · <a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The largest segments for customer interviews are intensive research (58) and code (44, 19 of them outside technical teams). For the 61 inactive people the question is different: what stops them from starting.</div><div class="fg"><span class="fk">In general</span>Data shows what people do but not whether the current tool is enough for them. So a segment is a hypothesis: it suggests whom to invite to customer interviews, which questions to ask, and what problems people may run into. Tool candidates appear already here, and the choice between them is made after the interviews, for a confirmed problem.</div><div class="fa"><span class="fk">Next step</span>For each segment, talk to 2–3 people: where the current tool falls short and what they still do by hand. Gather candidates for a confirmed problem from three sources: consultations with innovators inside the company, outside experts, and market benchmarks, meaning what similar companies use. Next, follow the <a href="#decision">decision procedure</a>: questionnaire, comparison, and testing candidates on real tasks. If the problem is not confirmed, postpone the segment until the next recount.</div></div></div></section><section class="chapter" id="layer2"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18"/></svg></span>Nature of work</h2><p><b>Goal:</b> show which tasks people solve with the tool, with which built-in features, and through which integrations.</p><div class="block"><h3 id="connectors">Connectors</h3><div class="dp dp-seq"><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="Without connectors the model answers with guesses" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="29" y="21" width="22" height="22" rx="6"/><path d="M40 21v-4"/><circle cx="36" cy="31" r="1.6" fill="currentColor"/><circle cx="44" cy="31" r="1.6" fill="currentColor"/><path d="M36 37h8"/><path stroke="var(--warn)" d="M77 13a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M80 21h.01"/><path stroke="var(--warn)" d="M97 29a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M100 37h.01"/><path stroke="var(--warn)" d="M81 45a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M84 53h.01"/><path stroke="var(--warn)" d="M117 17a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M120 25h.01"/><path stroke="var(--warn)" d="M115 43a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M118 51h.01"/></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="With connectors the model relies on work data" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="20" y="4" width="14" height="11" rx="2"/><rect x="40" y="4" width="14" height="11" rx="2"/><rect x="60" y="4" width="14" height="11" rx="2"/><path d="M27 15l13 8M47 15v6M67 15l-13 8"/><rect x="36" y="25" width="22" height="22" rx="6"/><path d="M47 25v-4"/><circle cx="43" cy="35" r="1.6" fill="currentColor"/><circle cx="51" cy="35" r="1.6" fill="currentColor"/><path d="M43 41h8"/><path d="M64 36H90M85 32l5 4-5 4"/><path d="M96 22h14l6 6v22h-20z"/><path d="M110 22v6h6"/><path d="M101 39l3 3 6-7"/></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="Share of wrong answers before and after connecting" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="30" y="10" width="18" height="46" rx="3" fill="var(--warn)" stroke="none" opacity=".85"/><rect x="88" y="42" width="18" height="14" rx="3" fill="currentColor" stroke="none"/><path d="M22 58h94" stroke="var(--line-2)"/><path d="M56 32H80M75 28l5 4-5 4"/></svg></div><p class="why">Connectors link the assistant to work data: chats, documents, code, calendars. They determine the volume of hallucinations: without access to data, the model fills in the answer itself. <b>Decision:</b> which teams and which systems to connect first.</p><div class="bars"><div class="bar"><span class="l">Slack</span><span class="tr"><span class="f" style="display:block;width:100%;background:var(--c-work)"></span></span><span class="v">520</span></div><div class="bar"><span class="l">Notion</span><span class="tr"><span class="f" style="display:block;width:65%;background:var(--c-work)"></span></span><span class="v">340</span></div><div class="bar"><span class="l">GitHub</span><span class="tr"><span class="f" style="display:block;width:40%;background:var(--c-work)"></span></span><span class="v">210</span></div><div class="bar"><span class="l">Calendar</span><span class="tr"><span class="f" style="display:block;width:29%;background:var(--c-work)"></span></span><span class="v">150</span></div></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage" target="_blank" rel="noopener">Overview</a> · "App interactions" block</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Slack and Notion account for 70% of all connections. The model does not see systems outside this list: it answers questions about them with a guess.</div><div class="fg"><span class="fk">In general</span>The volume of hallucinations drops where the model has the context it needs. Without it, the agent tries to fill the gap on its own. Teams with zero connections work with the model blind, and almost any answer about their processes is a guess. The sign in a customer interview: "I have to double-check everything".</div><div class="fa"><span class="fk">Next step</span>Find teams with zero connections and ask in interviews where their work data lives. Connect one such source and compare before and after on 10 identical questions: how many answers are wrong and how many rely on work data.</div></div></div><div class="block"><h3 id="skills">Skills</h3><div class="dp dp-seq"><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="One-off requests: a different result every time" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="22" cy="20" r="6"/><path d="M12.4 39.2c0-6.6 4.5-10.8 9.6-10.8s9.6 4.2 9.6 10.8"/></g><path d="M40 32H78M73 28l5 4-5 4"/><g stroke="var(--warn)"><path d="M92 2h10l4 4v14h-14z"/><path d="M95 9h8"/><path d="M95 13h5"/></g><g stroke="var(--warn)"><path d="M106 22h10l4 4v14h-14z"/><path d="M109 29h5"/><path d="M109 33h8"/><path d="M109 37h3"/></g><g stroke="var(--warn)"><path d="M92 42h10l4 4v14h-14z"/><path d="M95 49h3"/></g></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="A skill: the same result on every run" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><g stroke="var(--ink-2)"><circle cx="14" cy="20" r="6"/><path d="M4.4 39.2c0-6.6 4.5-10.8 9.6-10.8s9.6 4.2 9.6 10.8"/></g><path d="M30 32H46M41 28l5 4-5 4"/><rect x="50" y="16" width="24" height="32" rx="3"/><path d="M54 24l2 2 3-3M62 25h8"/><path d="M54 32l2 2 3-3M62 33h8"/><path d="M54 40l2 2 3-3M62 41h8"/><path d="M80 32H98M93 28l5 4-5 4"/><g><path d="M108 2h10l4 4v14h-14z"/><path d="M111 9h8"/><path d="M111 13h8"/><path d="M111 17h5"/></g><g><path d="M108 22h10l4 4v14h-14z"/><path d="M111 29h8"/><path d="M111 33h8"/><path d="M111 37h5"/></g><g><path d="M108 42h10l4 4v14h-14z"/><path d="M111 49h8"/><path d="M111 53h8"/><path d="M111 57h5"/></g></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="A shared skill: the same result across several teams" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="16" width="24" height="32" rx="3"/><path d="M10 24l2 2 3-3M18 25h8"/><path d="M10 32l2 2 3-3M18 33h8"/><path d="M10 40l2 2 3-3M18 41h8"/><path d="M32 32C48 32 52 11 68 11M32 32H68M32 32C48 32 52 53 68 53"/><g stroke="var(--ink-2)"><circle cx="80" cy="6" r="3.5"/><path d="M74.4 17.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g stroke="var(--ink-2)"><circle cx="94" cy="6" r="3.5"/><path d="M88.4 17.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g><path d="M110 2h10l4 4v14h-14z"/><path d="M113 9h8"/><path d="M113 13h8"/><path d="M113 17h5"/></g><g stroke="var(--ink-2)"><circle cx="80" cy="27" r="3.5"/><path d="M74.4 38.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g stroke="var(--ink-2)"><circle cx="94" cy="27" r="3.5"/><path d="M88.4 38.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g><path d="M110 23h10l4 4v14h-14z"/><path d="M113 30h8"/><path d="M113 34h8"/><path d="M113 38h5"/></g><g stroke="var(--ink-2)"><circle cx="80" cy="48" r="3.5"/><path d="M74.4 59.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g stroke="var(--ink-2)"><circle cx="94" cy="48" r="3.5"/><path d="M88.4 59.2c0-3.9 2.6-6.3 5.6-6.3s5.6 2.4 5.6 6.3"/></g><g><path d="M110 44h10l4 4v14h-14z"/><path d="M113 51h8"/><path d="M113 55h8"/><path d="M113 59h5"/></g></svg></div><p class="why">Skills show process maturity: a scenario once described as a skill repeats the same way for anyone who runs it. The stats show which skills are used and who builds their own. <b>Decision:</b> which processes can already be rolled out to other teams, and which still depend on individual people.</p><div class="bars"><div class="bar"><span class="l">spreadsheets</span><span class="tr"><span class="f" style="display:block;width:100%;background:var(--c-code)"></span></span><span class="v">88</span></div><div class="bar"><span class="l">pdf</span><span class="tr"><span class="f" style="display:block;width:65%;background:var(--c-code)"></span></span><span class="v">57</span></div><div class="bar"><span class="l">skill-creator</span><span class="tr"><span class="f" style="display:block;width:33%;background:var(--c-code)"></span></span><span class="v">29</span></div></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage" target="_blank" rel="noopener">Overview</a> · "Skills" block</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The spreadsheet and PDF skills have 88 and 57 calls: these processes are already reproducible. 29 calls to skill-creator: some people are turning their scenarios into skills.</div><div class="fg"><span class="fk">In general</span>Process maturity grows in steps: one-off requests → a personal skill → a shared team skill. At the first step, the result depends on who asked and how. With a skill it is reproducible: the same input gives the same result. A shared skill makes the process transferable to other teams.</div><div class="fa"><span class="fk">Next step</span>Collect skills into one list with their authors and mark the step of each process. Turn the two most used personal skills into shared ones: the author shows them to a neighboring team, and the team checks that the same inputs give the same result. Scenarios without a skill that repeat every week are the first candidates for new skills.</div></div></div><div class="block"><h3 id="projects">Project themes</h3><div class="dp dp-seq"><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="A project: files and instructions the model relies on" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 16h14l4 5h22v28H14z"/><path d="M22 32h10M22 38h16M22 44h12"/><path d="M58 34H78M73 30l5 4-5 4"/><rect x="87" y="23" width="22" height="22" rx="6"/><path d="M98 23v-4"/><circle cx="94" cy="33" r="1.6" fill="currentColor"/><circle cx="102" cy="33" r="1.6" fill="currentColor"/><path d="M94 39h8"/><path d="M114 34H128M123 30l5 4-5 4"/><path d="M134 30l3 3 6-7"/></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="Projects by theme reveal concrete tasks" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 12h14l4 5h22v28H14z"/><path d="M22 20h14l4 5h22v28H22z"/><path d="M30 28h14l4 5h22v28H30z"/><circle cx="104" cy="30" r="12"/><path d="M113 39l10 10"/><path d="M98 30h12M104 24v12"/><path d="M76 30H88M83 26l5 4-5 4"/></svg><span class="tt-ar" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><svg class="dp-v" style="color:var(--accent)" viewBox="0 0 150 64" role="img" aria-label="The project author is invited to a customer interview" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M10 16h14l4 5h22v28H10z"/><path d="M54 32H72M67 28l5 4-5 4"/><g stroke="var(--ink-2)"><circle cx="88" cy="22" r="6"/><path d="M78.4 41.2c0-6.6 4.5-10.8 9.6-10.8s9.6 4.2 9.6 10.8"/></g><path d="M104 10h32v18h-18l-7 6v-6h-7z"/><path d="M117 16a3 3 0 1 1 4 2.8c-.8.4-1 1-1 1.7M120 24.5h.01"/></svg></div><p class="why">The summary groups projects by meaning and shows the concrete tasks people run in ongoing projects. For customer interviews this is a ready list: which tasks to discuss and with whom. <b>Decision:</b> which tasks and whose projects to cover in interviews first.</p><div class="tbl"><table><thead><tr><th>Theme</th><th class="r">Projects</th><th>Tasks</th><th>Question for the author</th></tr></thead><tbody><tr><td>Sales<small class="pt-s">Pitch library · Elif Demir</small></td><td class="r">11</td><td>pitches, objection handling, commercial proposals</td><td class="pt-q">"Which part of a pitch does the model do well, and what do you rewrite?"</td></tr><tr><td>Onboarding<small class="pt-s">New hire guide · Rafael Costa</small></td><td class="r">8</td><td>guides for newcomers, answers to typical questions</td><td class="pt-q">"Which newcomer questions does the model already handle without you?"</td></tr><tr><td>Market research<small class="pt-s">Competitor notes · Jonas Keller</small></td><td class="r">5</td><td>competitor summaries, price comparisons</td><td class="pt-q">"Where do you get the data, and how quickly does it go stale?"</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage/projects" target="_blank" rel="noopener">Projects</a> · names grouped by meaning</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Sales (11) and onboarding (8) have the most standing projects. The authors of the largest projects are the first people to interview.</div><div class="fg"><span class="fk">In general</span>A project is a knowledge base: files and instructions the model relies on in every answer. The fuller the base, the more accurate and stable the result. What a project contains suggests what to ask in an interview: which files were added, what is missing, and where answers still need fixing.</div><div class="fa"><span class="fk">Next step</span>Open the three most active projects in each theme and list the concrete tasks. In the interview, ask the author the question from the table and which files and instructions changed answer quality the most. Turn a successful project setup into a template for that theme.</div></div></div></section><section class="chapter" id="layer3"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8.5 12l2.5 2.5 4.5-5"/></svg></span>Verification</h2><p><b>Goal:</b> check the summaries against the raw exports, the project list and the leaderboard. Any number in the report can be traced back to its source row in an export.</p><div class="block"><h3>Full project list</h3><p class="why">All projects with author and status. This list is used to check the theme summary and to find the author of a specific project.</p><div class="tbl"><table><thead><tr><th>Project</th><th>Author</th><th>Status</th><th class="r">Msgs</th></tr></thead><tbody><tr><td>Pitch library</td><td>Elif Demir</td><td><span class="pill"><i style="background:var(--c-work)"></i>active</span></td><td class="r">268</td></tr><tr><td>Price list 2026</td><td>Oskar Berg</td><td><span class="pill"><i style="background:var(--c-work)"></i>active</span></td><td class="r">64</td></tr><tr><td>Personal draft</td><td>Pavel Novak</td><td><span class="pill"><i style="background:var(--c-none)"></i>abandoned</span></td><td class="r">0</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://chatgpt.com/admin/usage/projects" target="_blank" rel="noopener">Projects</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The "Personal draft" project has zero messages.</div><div class="fg"><span class="fk">In general</span>An empty project is an abandoned attempt: the person started, but the tool never became part of their work. If such projects stay in, the topic summary overstates usage.</div><div class="fa"><span class="fk">Next step</span>Filter out projects with zero messages before counting and invite 2–3 of their authors: the reason they quit is a valuable answer.</div></div></div><div class="block"><h3>Leaderboard</h3><p class="why">The billing export for each person and product. Main tools and top lists are calculated from it.</p><div class="tbl"><table><thead><tr><th>Name</th><th>Email</th><th class="r">Credits</th><th class="r">$</th></tr></thead><tbody><tr><td>Hana Sato</td><td><!--email_off-->hana&#64;example.com<!--/email_off--></td><td class="r">10,955</td><td class="r">438.20</td></tr><tr><td>Mira Castellano</td><td><!--email_off-->mira&#64;example.com<!--/email_off--></td><td class="r">2,425</td><td class="r">97.00</td></tr><tr><td>Jonas Keller</td><td><!--email_off-->jonas&#64;example.com<!--/email_off--></td><td class="r">470</td><td class="r">18.80</td></tr></tbody></table></div><p class="cap src-cap">Source: <a href="https://admin.openai.com" target="_blank" rel="noopener">Leaderboard</a> · three exports with different "Product" filters</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The three product exports add up to the total spend of each person on the list.</div><div class="fg"><span class="fk">In general</span>The three exports with different Product filters add up to each person's total spend. A gap above 2% means an export is incomplete or the periods differ.</div><div class="fa"><span class="fk">Next step</span>Before sharing the report, sum the three exports per person and compare with total spend. If they differ, re-export the data for the same period.</div></div></div></section><section class="chapter" id="layer4"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg></span>People selection</h2><p><b>Goal:</b> name specific people for each way of getting tasks done.</p><div class="block"><h3 id="candidates">Interview candidates</h3><p class="why">A short list of people for each direction found. In the example the final list is 16 people out of 340; the table shows the first three. Your company will have its own number. The ChatGPT report is one of the sample sources: users of other tools and people who quit are added by the rules in <a href="/en/blog/who-to-interview-before-buying-ai-tools/#groups">"Who to interview"</a>, and the check across all employees is done with a <a href="/en/blog/ai-interviews-without-leading-questions/#form">questionnaire</a>.</p><div class="tbl"><table><thead><tr><th>Person</th><th>Direction</th><th class="r">Signal</th></tr></thead><tbody><tr><td>Hana Sato</td><td><span class="pill"><i style="background:var(--c-code)"></i>code</span></td><td class="r">$438 / 3 mo</td></tr><tr><td>Mira Castellano</td><td><span class="pill"><i style="background:var(--c-work)"></i>agentic tasks</span></td><td class="r">$97 / 3 mo</td></tr><tr><td>Jonas Keller</td><td><span class="pill"><i style="background:var(--c-chat)"></i>research</span></td><td class="r">3,200+ msgs</td></tr></tbody></table></div><p class="cap src-cap">Source: the users, leaderboard and projects exports, joined by email</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Hana Sato, Mira Castellano, and Jonas Keller represent three different ways of working: code, agentic tasks, and research.</div><div class="fg"><span class="fk">In general</span>The shortlist has one person per direction: code, agent tasks, research. Each conversation then shows its own way of working and does not repeat another one.</div><div class="fa"><span class="fk">Next step</span>Schedule three interviews, one per direction. Afterwards, decide which direction needs 2–3 more people.</div></div></div><div class="block"><h3 id="people">Table of all people</h3><p class="why">Everyone, with filters by team, activity, direction, and main tool.</p><div class="chips"><span class="chip">Team B</span><span class="chip">Activity: every week</span><span class="chip on">Tool: Work</span></div><div class="tbl"><table><thead><tr><th>Person</th><th>Team</th><th>Chat / Work</th><th class="r">$ / 3 mo</th></tr></thead><tbody><tr><td>Tomás Reid</td><td>Team B</td><td><div class="mix"><span style="width:28%;background:var(--c-chat)"></span><span style="width:72%;background:var(--c-work)"></span></div></td><td class="r">112.00</td></tr><tr><td>Mira Castellano</td><td>Team B</td><td><div class="mix"><span style="width:35%;background:var(--c-chat)"></span><span style="width:65%;background:var(--c-work)"></span></div></td><td class="r">97.00</td></tr></tbody></table></div><p class="cap src-cap">Source: the users, leaderboard and projects exports, joined by email</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The "Team B" and "Tool: Work" filters left two people: Mira Castellano and Tomás Reid.</div><div class="fg"><span class="fk">In general</span>A table of all people with filters by team, activity and main tool is the base for any next sample: a list for a new question needs no new export.</div><div class="fa"><span class="fk">Next step</span>Save each set of filters as a separate table view so the next list takes one click.</div></div></div></section><section class="chapter" id="start"><h2>Where to start today</h2><p>You do not need the whole report at once: the first useful result, a list of most active users, appears after the second item.</p><ul class="todo"><li><span class="box" aria-hidden="true"></span><div><b>Export users and the leaderboard for three months</b><span class="d">The leaderboard three times, once per product. A browser agent can do the export</span><div class="step-l"><a href="https://claude.com/claude-in-chrome" target="_blank" rel="noopener">Claude in Chrome <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 17L17 7M8 7h9v9"/></svg></a><a href="https://support.google.com/gemini/answer/16821166" target="_blank" rel="noopener">Gemini in Chrome <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 17L17 7M8 7h9v9"/></svg></a><a href="https://www.perplexity.ai/comet" target="_blank" rel="noopener">Perplexity Comet <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 17L17 7M8 7h9v9"/></svg></a></div></div></li><li><span class="box" aria-hidden="true"></span><div><b>Calculate main tools and the top by amount</b><span class="d">The first list of most active users is ready</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Calculate adoption depth</b><span class="d">At least once / regularly / every week, with those who work only through Codex counted separately</span></div></li><li><span class="box" aria-hidden="true"></span><div><b>Build a list of people and schedule interviews</b><span class="d">How to pick these people is covered in "Who to interview"</span></div></li></ul><div class="sublabel" style="margin-top:22px">Common questions</div><div class="qa"><div><h3>What the ChatGPT Enterprise admin console shows</h3><p>Five sections: users, leaderboard, projects, overview and tasks. They give adoption depth, uniformity across teams, the main tool, the nature of tasks and a check against raw data.</p></div><div><h3>How to export data from the console</h3><p>The console has APIs, but they cover only part of the data: Codex analytics, credit costs and conversation logs for compliance. The users, projects and skills exports and the per-product leaderboard are easier to collect in the interface, and the export can be handed to Claude in Chrome.</p></div><div><h3>How to tell whether new licenses are needed</h3><p>Adoption depth shows how many people use the tool at least once, regularly and every week. It decides which group to train and whether to buy new licenses now.</p></div><div><h3>How to choose people to interview</h3><p>People are picked for each direction found: in the example the final list is 16 people out of 340. Users of other tools and those who stopped are added by the rules in <a href="/en/blog/who-to-interview-before-buying-ai-tools/">“Who to interview”</a>.</p></div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links"><a href="/en/blog/who-to-interview-before-buying-ai-tools/"><div class="k">Interviews</div><div class="t">Who to interview</div><div class="d">How to build an interview sample from the table of people</div></a><a href="/en/blog/ai-interviews-without-leading-questions/"><div class="k">Interviews</div><div class="t">How to interview people about their AI use</div><div class="d">A call, a survey and one Airtable table</div></a></div></section><footer>All names, teams, addresses, and numbers in the examples are fictional.</footer></div>]]></content:encoded></item>
<item><title>Harness engineering in practice: turning AI agent mistakes into rules of its environment (HDD)</title><link>https://www.urvanov.com/en/blog/harness-driven-development/</link><guid>https://www.urvanov.com/en/blog/harness-driven-development/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>The mistake-to-rule loop, guides and sensors, three layers of checks, how it fits with specs, and five first steps in your own project.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>Harness engineering</strong> is the work of shaping the environment around an AI agent: instructions, tools, permissions and checks. <strong>Harness-Driven Development (HDD)</strong> is a working method built on it: every agent mistake becomes a rule of that environment.</p>
<div class="s-rich s-rich-hdd-en"><div class="ladder" role="img" aria-label="Three stages of working with AI: prompt, context, harness"><div class="st s1"><span class="n">1</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg><b>Prompt</b><small>the request wording</small></div><div class="st s2"><span class="n">2</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg><b>Context</b><small>what the model knows</small></div><div class="st s3"><span class="n">3</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg><b>Harness</b><small>the agent's <a class="st-l" href="/en/blog/ai-in-code-harness-and-tools/">environment</a></small><em>HDD</em></div></div><p class="cap">Stages as described by <a href="https://www.faros.ai/blog/harness-engineering" target="_blank" rel="noopener">Faros</a> and <a href="https://marmelab.com/blog/2026/09/24/the-state-of-ai-harness-engineering-2026.html" target="_blank" rel="noopener">marmelab</a></p><section class="chapter" id="stages"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 20h5v-5h5v-5h5V5h3"/></svg></span>Three stages</h2><div class="cmp3"><div class="c3"><div class="c3-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg>Prompt</div><div class="c3-v"><span class="chip">role</span><span class="chip">format</span><span class="chip">example</span></div><div class="c3-s"><span class="k">fixes</span>one request</div></div><div class="c3"><div class="c3-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Context</div><div class="c3-v"><span class="chip">documents</span><span class="chip">project</span><span class="chip">memory</span></div><div class="c3-s"><span class="k">fixes</span>what the model knows</div></div><div class="c3 on"><div class="c3-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>Harness</div><div class="c3-v"><span class="chip">tools</span><span class="chip">tests</span><span class="chip">rules</span><span class="chip">permissions</span></div><div class="c3-s"><span class="k">fixes</span>every future run</div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A prompt fixes one answer, context fixes what the model knows, and the harness fixes every future agent run.</div><div class="fg"><span class="fk">In general</span>Harness-Driven Development is work at the third stage: the developer writes less code and spends more time setting up the environment where the agent writes, checks and fixes it.</div><div class="fa"><span class="fk">Next step</span>Write down the agent's last three mistakes and mark the stage at which each could have been fixed for good.</div></div></section><section class="chapter" id="loop"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span>The HDD loop</h2><div class="loopwrap"><svg class="lp" viewBox="0 0 900 400" role="img" aria-label="Loop: task, agent, result, sensors; if a mistake is found, a new rule goes into the harness and the next task runs with it"><title>Task → agent → result → sensors → mistake → rule in the harness → next task</title><defs><marker id="lp-ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="lp-arh"/></marker></defs><rect class="lp-h" x="250" y="20" width="400" height="360" rx="28"/><text class="lp-ht" x="450" y="52" text-anchor="middle">harness</text><rect class="lp-n" x="30" y="165" width="150" height="60" rx="8"/><text class="lp-t" x="105" y="201" text-anchor="middle">Task</text><rect class="lp-n key" x="300" y="80" width="150" height="60" rx="8"/><text class="lp-t" x="375" y="116" text-anchor="middle">Agent</text><rect class="lp-n" x="720" y="80" width="150" height="60" rx="8"/><text class="lp-t" x="795" y="116" text-anchor="middle">Result</text><rect class="lp-n sen" x="520" y="165" width="150" height="60" rx="8"/><text class="lp-t" x="595" y="201" text-anchor="middle">Sensors</text><rect class="lp-n rule" x="300" y="280" width="200" height="64" rx="8"/><text class="lp-t" x="400" y="310" text-anchor="middle">New rule</text><text class="lp-s" x="400" y="331" text-anchor="middle">instruction · test · hook</text><circle class="lp-ok" cx="795" cy="290" r="26"/><path class="lp-okm" d="M783,290 l8,8 l16,-17"/><path class="lp-e" d="M180,195 C 230,195 250,110 298,110" marker-end="url(#lp-ar)"/><path class="lp-e" d="M450,110 L718,110" marker-end="url(#lp-ar)"/><text class="lp-el" x="585" y="100" text-anchor="middle">produces</text><path class="lp-e" d="M760,140 C 740,170 700,190 672,195" marker-end="url(#lp-ar)"/><text class="lp-el" x="742" y="180" text-anchor="start">check</text><path class="lp-e ok" d="M670,210 C 720,250 750,270 767,282" marker-end="url(#lp-ar)"/><text class="lp-el ok" x="712" y="262" text-anchor="end">passed</text><path class="lp-e bad" d="M560,225 C 540,270 520,300 502,308" marker-end="url(#lp-ar)"/><text class="lp-el bad" x="555" y="270" text-anchor="start">mistake</text><path class="lp-e bad" d="M340,280 C 330,230 350,170 370,142" marker-end="url(#lp-ar)"/><text class="lp-el bad" x="372" y="236" text-anchor="start">won't happen again</text></svg></div><p class="cap">Mitchell Hashimoto's principle: when the agent makes a mistake, change the harness so that mistake can't happen again <a href="https://www.faros.ai/blog/harness-engineering" target="_blank" rel="noopener">Faros</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A mistake caught by the sensors goes into the harness as a new rule, and the agent gets that rule on every following run.</div><div class="fg"><span class="fk">In general</span>A result fixed by hand helps once. A rule in the harness (an instruction, a test or a hook) applies to all future tasks, so the harness gets more precise over time without changing the model.</div><div class="fa"><span class="fk">Next step</span>Adopt a rule: any agent mistake you had to fix by hand becomes a line in the instructions or a test on the same day.</div></div></section><section class="chapter" id="canons"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></span>How a harness is laid out: 3 × 3</h2><p class="why">Three domains of the loop and three contexts in each — nine canons. Every canon has exactly one domain and one context.</p><div class="cn" role="img" aria-label="How a harness is laid out: 3 × 3"><div class="cn-c"></div><div class="cn-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg><b>Spec</b><small>what must be true</small></div><div class="cn-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg><b>Skill</b><small>how to act</small></div><div class="cn-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg><b>Memory</b><small>what to rely on</small></div><div class="cn-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg><b>Expectation</b><small>what should be</small></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg>Spec</em><span class="chip">genres, schemas</span><span class="chip">requirement levels</span><span class="chip">number passport</span></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>Skill</em><span class="chip">prediction before acting</span></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>Memory</em><span class="chip">actuator roles</span><span class="chip">live · MCP</span></div><div class="cn-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg><b>Observation</b><small>what was measured</small></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg>Spec</em><span class="chip">evidence rank</span><span class="chip">finding format</span><span class="chip">scale</span></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>Skill</em><span class="chip">sensor records the fact</span></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>Memory</em><span class="chip">live only</span></div><div class="cn-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg><b>Loop</b><small>compare and decide</small></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg>Spec</em><span class="chip">rule completeness criteria</span><span class="chip">findings registry</span></div><div class="cn-x"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>Skill</em><span class="chip">compare</span><span class="chip">count repeats</span><span class="chip">patch or revise</span></div><div class="cn-x empty"><em class="cn-k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>Memory</em><small>empty for now</small></div></div><div class="cf" role="img" aria-label="Expectation + Observation → Loop → patch / revise rules"><div class="cf-l"><span class="cf-n a"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg>Expectation</span><span class="cf-n b"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>Observation</span></div><div class="cf-ar"><svg viewBox="0 0 80 120" aria-hidden="true"><path d="M4,26 C 40,26 40,60 74,60" class="cf-e"/><path d="M4,94 C 40,94 40,60 74,60" class="cf-e"/><path d="M66,54 L76,60 L66,66" class="cf-e"/></svg></div><div class="cf-m"><span class="cf-n c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg>Loop</span><span class="cf-no">✕ no reverse link</span></div><div class="cf-ar"><svg viewBox="0 0 80 120" aria-hidden="true"><path d="M4,60 C 40,60 40,26 72,26" class="cf-e"/><path d="M4,60 C 40,60 40,94 72,94" class="cf-e"/><path d="M64,21 L74,26 L64,31 M64,89 L74,94 L64,99" class="cf-e"/></svg></div><div class="cf-r"><span class="cf-o">patch</span><span class="cf-o rev">revise rules</span></div></div><div class="cf-note"><span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>→<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg></span>skill → spec of its domain<i>·</i>a commit hook script checks the direction</div><div class="mm"><div class="mm-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg><b>snapshot</b><small>a table, updated after each new measurement</small></div><div class="mm-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12a7 7 0 0 1 14 0M8.5 12a3.5 3.5 0 0 1 7 0"/><circle cx="12" cy="12" r="1.2"/><path d="M12 13v7"/></svg><b>live</b><small>a protocol, fresh every time, nothing stored</small></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The loop splits into Expectation, Observation and Loop, each with its own spec, skill and memory. Loop reads the other two domains; they never read Loop.</div><div class="fg"><span class="fk">In general</span>It is a negative feedback loop: the target value is compared with the measured one, and something changes only on a mismatch. A strict reference direction keeps the domains from tangling, and the same concept repeating in two domains is not a defect.</div><div class="fa"><span class="fk">Next step</span>Sort the files of your harness into the nine cells and check that no Expectation or Observation file refers to Loop.</div></div></section><section class="chapter" id="double"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12a5 5 0 0 1 9-3"/><path d="M13 5v4h-4"/><path d="M20 12a8 8 0 1 1-4-6.9"/><path d="M20 3v5h-5"/></svg></span>The double loop</h2><div class="dl"><div class="dl-a"><svg viewBox="0 0 120 120" aria-hidden="true"><circle cx="60" cy="60" r="34" class="dl-c1"/><path d="M88,40 l6,-10 l4,11" class="dl-c1"/></svg><b>single loop</b><small>fix the action under the same rules</small></div><div class="dl-a on"><svg viewBox="0 0 120 120" aria-hidden="true"><circle cx="60" cy="60" r="24" class="dl-c1"/><circle cx="60" cy="60" r="46" class="dl-c2"/><path d="M100,34 l6,-10 l4,11" class="dl-c2"/></svg><b>double loop</b><small>change the rules themselves</small></div></div><div class="pr4"><div class="pr4-c"><span class="pr4-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17c3-6 5 2 8-4s5 2 8-4"/><path d="M4 20h16"/></svg></span><b>Patches without a new prediction</b><small>fix it with a rule</small></div><div class="pr4-c"><span class="pr4-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.7 3h10.6a2 2 0 0 0 1.7-3l-5-9V3"/></svg></span><b>Several complaints</b><small>first test for a shared cause</small></div><div class="pr4-c"><span class="pr4-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/><path d="M12 8v4l3 2"/></svg></span><b>A new rule</b><small>accepted only if old cases follow from it</small></div><div class="pr4-c"><span class="pr4-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/><path d="M9 12l2 2 4-4"/></svg></span><b>No external check</b><small>discard it, with a record</small></div></div><p class="cap">The loop applies to itself: every run ends with the residual risk, never with a “done” status.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A series of patches, complaints, a new rule and an external check are four checkable principles the Loop uses to decide whether to fix the action or change the rules.</div><div class="fg"><span class="fk">In general</span>A single loop fixes the result within the old rules. A double loop changes the rules themselves, and does it by checkable principles, so the harness learns without drifting from random edits.</div><div class="fa"><span class="fk">Next step</span>When the same fix comes up a third time, stop and ask which rule causes it. Change the rule only if it also explains the old cases.</div></div></section><section class="chapter" id="controls"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></span>Guides and sensors</h2><div class="gs" role="img" aria-label="Matrix: guides act before the agent, sensors after; each is either computational or AI-based"><div class="gs-c"></div><div class="gs-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg><b>Guides</b><small>before the action</small></div><div class="gs-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg><b>Sensors</b><small>after the action</small></div><div class="gs-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4"/></svg><b>Computational</b><small>fast · reliable</small><span class="spd"><i class="on"></i><i class="on"></i><i class="on"></i></span></div><div class="gs-x"><span class="chip">types</span><span class="chip">code templates</span><span class="chip">generators</span></div><div class="gs-x"><span class="chip">tests</span><span class="chip">linter</span><span class="chip">type checking</span></div><div class="gs-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z"/></svg><b>AI-based</b><small>flexible · costlier</small><span class="spd"><i class="on"></i><i></i><i></i></span></div><div class="gs-x"><span class="chip">AGENTS.md · CLAUDE.md</span><span class="chip">skills</span><span class="chip">specs</span></div><div class="gs-x"><span class="chip">AI review</span><span class="chip">LLM judge</span></div></div><p class="cap">Split as described in <a href="https://martinfowler.com/articles/harness-engineering.html" target="_blank" rel="noopener">Martin Fowler: Harness engineering</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Four cells: guides set the course before the agent works, sensors catch deviations afterwards, and each can be computational or AI-based.</div><div class="fg"><span class="fk">In general</span>Computational checks run in seconds and don't make mistakes, so use them wherever a rule can be written down formally. Keep AI-based checks for meaning: style, clarity, fit with the intent.</div><div class="fa"><span class="fk">Next step</span>For each rule in the agent's instructions, ask whether a test or linter could check it. If so, move it there.</div></div></section><section class="chapter" id="layers"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 5-9 5-9-5 9-5z"/><path d="M3 13l9 5 9-5"/></svg></span>Three check layers</h2><div class="ly" role="img" aria-label="Three layers: code quality is the most mature, architecture is in the middle, behavior is the least mature"><div class="ly-r"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4l6 6M4 20c2-6 6-10 10-10l2 2c0 4-4 8-10 10z"/></svg></span><b>Code quality</b><div class="ly-bar"><i style="width:88%"></i></div><span class="ly-m">mature</span></div><div class="ly-r"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="6" rx="1"/><rect x="14" y="15" width="7" height="6" rx="1"/><rect x="14" y="3" width="7" height="6" rx="1"/><path d="M10 6h4M17.5 9v6"/></svg></span><b>Architecture</b><div class="ly-bar"><i style="width:55%"></i></div><span class="ly-m">growing</span></div><div class="ly-r"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg></span><b>Behavior</b><div class="ly-bar"><i style="width:25%"></i></div><span class="ly-m">hardest</span></div></div><p class="cap">Layer maturity as assessed by <a href="https://martinfowler.com/articles/harness-engineering.html" target="_blank" rel="noopener">Martin Fowler</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Code quality is the easiest to check today, and product behavior the hardest.</div><div class="fg"><span class="fk">In general</span>Linters and formatters cover the first layer almost immediately. Architecture is checked with dependency rules and performance requirements. Behavior still needs good scenario tests and a human eye.</div><div class="fa"><span class="fk">Next step</span>Start with the first layer: run a linter and formatter on every agent run, then add one rule for module boundaries.</div></div></section><section class="chapter" id="shift"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>Earlier is cheaper</h2><div class="sh" role="img" aria-label="The earlier a check runs, the cheaper the mistake: before the agent starts, on write, in CI, at review"><div class="sh-s"><span class="sh-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><b>Before work</b><small>instructions · specs</small><span class="usd">$</span></div><div class="sh-s"><span class="sh-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4"/></svg></span><b>On write</b><small>hooks · linter</small><span class="usd">$$</span></div><div class="sh-s"><span class="sh-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v6h-6"/></svg></span><b>In CI</b><small>tests · build</small><span class="usd">$$$</span></div><div class="sh-s"><span class="sh-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg></span><b>At review</b><small>a person</small><span class="usd">$$$$</span></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The same mistake costs least before the agent starts and most at human review.</div><div class="fg"><span class="fk">In general</span>Put fast checks as early as possible: the agent fixes the problem itself while the task context is still in front of it, and only the debatable points reach a person.</div><div class="fa"><span class="fk">Next step</span>Wire tests and the linter into a hook the agent runs after every edit, in addition to CI.</div></div></section><section class="chapter" id="human"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg></span>Where people matter</h2><div class="hm" role="img" aria-label="The harness handles routine checks; a person decides architecture and product questions and improves the harness itself"><div class="hm-a"><div class="hm-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg>Harness</div><div class="dots"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div><small>style · types · tests · boundaries</small></div><div class="hm-b"><div class="hm-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg>Person</div><div class="dots"><i></i><i></i><i></i><i></i><i></i><i></i></div><small>architecture · product · new rules</small></div></div><p class="cap">"A good harness keeps the human in the loop and directs their attention to where it matters most" — paraphrasing <a href="https://martinfowler.com/articles/harness-engineering.html" target="_blank" rel="noopener">Martin Fowler</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The harness takes most of the checks; the person keeps the decisions and the work of improving the harness.</div><div class="fg"><span class="fk">In general</span>An experienced developer carries an implicit harness in their head: knowledge of the architecture, team habits, a feel for risk. HDD moves that knowledge into explicit rules, so every agent run gets it.</div><div class="fa"><span class="fk">Next step</span>After each review of the agent's code, write down one comment that keeps coming up and turn it into a rule.</div></div></section><section class="chapter" id="spec"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg></span>HDD and specs</h2><div class="sp" role="img" aria-label="The spec sets the goal; the harness checks that the agent reached it"><div class="sp-a"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg><b>Spec</b><small>the result you need</small></div><div class="sp-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="sp-b"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></svg><b>Harness</b><small>how to check you got it</small></div><div class="sp-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="sp-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l3 3 5-6"/></svg><b>Accepted code</b><small>no line-by-line manual review</small></div></div><p class="cap">"Specs define the target state, the harness is the control system" — <a href="https://loiane.com/2026/04/harness-engineering-missing-layer-specs-driven-ai-development/" target="_blank" rel="noopener">Loiane Groner</a>. More on specs in the talk <a href="/en/talk/spec-driven-development/">Spec-Driven Development in practice</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The spec answers "what are we building", the harness answers "how do we know we built it".</div><div class="fg"><span class="fk">In general</span>Without a spec the harness has nothing to check, and without a harness the spec stays a document. Together they let you accept the agent's code based on checks instead of reading every line.</div><div class="fa"><span class="fk">Next step</span>For each requirement in the spec, write down which test or check will confirm it is met.</div></div></section><section class="chapter" id="start"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 21V4M5 4h11l-2 4 2 4H5"/></svg></span>Where to start</h2><ol class="steps"><li><span class="step-n">1</span><div><div class="step-t">An instructions file for the agent</div><div class="step-d">AGENTS.md or CLAUDE.md in the project root: how to build, how to test, what not to do</div></div></li><li><span class="step-n">2</span><div><div class="step-t">Linter and tests after every edit</div><div class="step-d">a hook the agent runs itself before handing over the result</div></div></li><li><span class="step-n">3</span><div><div class="step-t">An agent mistake log</div><div class="step-d">every mistake fixed by hand gets a line with its cause</div></div></li><li><span class="step-n">4</span><div><div class="step-t">Mistake → rule</div><div class="step-d">once a week, move log entries into instructions, tests or hooks</div></div></li><li><span class="step-n">5</span><div><div class="step-t">A progress file for long tasks</div><div class="step-d">a feature list with statuses and the commit history, so a new session picks up where the last one stopped <a href="https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents" target="_blank" rel="noopener">Anthropic</a></div></div></li></ol><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Five steps: two set up the harness right away, three start the "mistake → rule" loop.</div><div class="fg"><span class="fk">In general</span>Nobody designs a harness in full up front. It grows out of the agent's real mistakes in your project, and within a few weeks the agent stops repeating the most common ones.</div><div class="fa"><span class="fk">Next step</span>Today, create the instructions file and the mistake log. In a week, move the first log entries into rules.</div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/work-prompts-examples/"><div class="k">Stage 1–2</div><div class="t">Prompts for work tasks</div><div class="d">how to write a single request and supply data</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Stage 3</div><div class="t">Comparing harnesses</div><div class="d">Claude Code, Codex, Cursor, Hermes and chat</div></a></div><p class="cap">More to read: <a href="https://martinfowler.com/articles/harness-engineering.html" target="_blank" rel="noopener">Martin Fowler</a> · <a href="https://www.anthropic.com/engineering/harness-design-long-running-apps" target="_blank" rel="noopener">Anthropic: Harness design</a> · <a href="https://leanpub.com/becoming-a-harness-driven-developer" target="_blank" rel="noopener">Becoming a Harness-Driven Developer</a> · <a href="https://github.com/ai-boost/awesome-harness-engineering" target="_blank" rel="noopener">awesome-harness-engineering</a></p></section><footer>Terms and the layer split follow the sources linked in the captions under the diagrams.</footer></div>]]></content:encoded></item>
<item><title>Approaches to working with a harness: the answer loop and review that fixes the original request</title><link>https://www.urvanov.com/en/blog/harness-work-approaches/</link><guid>https://www.urvanov.com/en/blog/harness-work-approaches/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>What to do when an answer misses: three paths and a repeated loop. How review finds gaps, why they go into the original request and the pipeline runs again. Based on Anthropic, OpenAI and Google guides.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-prompts-en"><div class="flow lead" aria-label="Two approaches: the answer loop and review that fixes the request"><div class="lane"><div class="lane-h" style="color:var(--warn)"><span class="dot" style="background:var(--warn)"></span>Answer missed</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg><b>Answer</b><small>off the task</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg><b>One of three paths</b><small>refine, redo, ask</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="14" height="14" rx="3"/><path d="M12 8.5l1.2 2.3 2.3 1.2-2.3 1.2-1.2 2.3-1.2-2.3-2.3-1.2 2.3-1.2z"/></svg><b>New answer</b><small>checked again</small></span></div></div><div class="lane"><div class="lane-h" style="color:var(--accent)"><span class="dot" style="background:var(--accent)"></span>Review found a gap</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><b>Request v1</b><small>the original task</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.3-4.3"/></svg><b>Review</b><small>two gaps</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg><b>Request v2</b><small>and the whole pipeline again</small></span></div></div></div><p class="cap">Both approaches work in any harness: a chat, Claude Code, Codex or Cursor.</p><section class="chapter" id="iterate"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3.5M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14.9 3.5M20 20v-4h-4"/></svg></span>If the answer misses</h2><div class="rv-wrap"><svg class="rv" viewBox="0 0 930 390" role="img" aria-label="If the answer misses there are three paths: the model understood the task — refine in the same chat; it misunderstood or made facts up — rewrite the request with the missing data and permission to say “I don’t know”, and send it in a new chat; it is unclear what is needed — first ask for three questions and build a six-part prompt from the answers. Each path gives a new answer; if it misses again, the loop repeats"><title>If the answer misses there are three paths: the model understood the task — refine in the same chat; it misunderstood or made facts up — rewrite the request with the missing data and permission to say “I don’t know”, and send it in a new chat; it is unclear what is needed — first ask for three questions and build a six-part prompt from the answers. Each path gives a new answer; if it misses again, the loop repeats</title><defs><marker id="it-ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="rv-arh"/></marker><marker id="it-arb" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" style="fill:var(--c-team)"/></marker></defs><rect class="rv-n bad" x="10" y="20" width="140" height="290" rx="7"/><path class="rv-x" d="M69,140 l22,22 M91,140 l-22,22"/><text class="rv-t" x="80" y="190" text-anchor="middle">Answer</text><text class="rv-t" x="80" y="210" text-anchor="middle">missed</text><path class="rv-e " d="M150,65 L288,65" marker-end="url(#it-ar)"/><text class="rv-el" x="219" y="57" text-anchor="middle">task understood</text><rect x="290" y="30" width="6" height="70" rx="2" style="fill:var(--c-chat)"/><rect class="rv-n req" x="290" y="30" width="230" height="70" rx="7"/><text class="rv-t" x="308" y="60" text-anchor="start">Refine in the same chat</text><text class="rv-q" x="308" y="82" text-anchor="start">“shorter”, “softer tone”</text><path class="rv-e " d="M520,65 L710,65" marker-end="url(#it-ar)"/><text class="rv-el" x="615" y="57" text-anchor="middle">same context</text><path class="rv-e " d="M150,165 L288,165" marker-end="url(#it-ar)"/><text class="rv-el" x="219" y="157" text-anchor="middle">misunderstood</text><text class="rv-el" x="219" y="183" text-anchor="middle">or made facts up</text><rect x="290" y="130" width="6" height="70" rx="2" style="fill:var(--c-proj)"/><rect class="rv-n req" x="290" y="130" width="230" height="70" rx="7"/><text class="rv-t" x="308" y="160" text-anchor="start">Rewrite the request</text><text class="rv-q" x="308" y="182" text-anchor="start">+ data, “I don’t know” ok</text><path class="rv-e " d="M520,165 L544,165" marker-end="url(#it-ar)"/><rect class="rv-n key" x="546" y="136" width="150" height="58" rx="7"/><text class="rv-t sm" x="621" y="170" text-anchor="middle">New chat</text><path class="rv-e " d="M696,165 L710,165" marker-end="url(#it-ar)"/><path class="rv-e " d="M150,265 L288,265" marker-end="url(#it-ar)"/><text class="rv-el" x="219" y="257" text-anchor="middle">needs unclear</text><rect x="290" y="230" width="6" height="70" rx="2" style="fill:var(--c-code)"/><rect class="rv-n req" x="290" y="230" width="230" height="70" rx="7"/><text class="rv-t" x="308" y="260" text-anchor="start">First, 3 questions</text><text class="rv-q" x="308" y="282" text-anchor="start">questions → your answers</text><path class="rv-e " d="M520,265 L544,265" marker-end="url(#it-ar)"/><rect class="rv-n key" x="546" y="236" width="150" height="58" rx="7"/><text class="rv-t sm" x="621" y="270" text-anchor="middle">Prompt · 6 parts</text><path class="rv-e " d="M696,265 L710,265" marker-end="url(#it-ar)"/><rect class="rv-n" x="712" y="20" width="88" height="290" rx="7"/><text class="rv-t" x="756" y="160" text-anchor="middle">New</text><text class="rv-t" x="756" y="180" text-anchor="middle">answer</text><path class="rv-e " d="M800,165 L818,165" marker-end="url(#it-ar)"/><rect class="rv-n good" x="820" y="130" width="100" height="70" rx="7"/><path class="rv-ok big" d="M858,150 l7,7 l14,-15"/><text class="rv-t sm" x="870" y="186" text-anchor="middle">Fits</text><path class="rv-e back" d="M756,310 L756,350 L80,350 L80,314" marker-end="url(#it-arb)"/><text class="rv-bl" x="416" y="374" text-anchor="middle">↺ missed again — next round</text></svg><svg class="rv rv-v" viewBox="0 0 360 738" role="img" aria-label="If the answer misses there are three paths: the model understood the task — refine in the same chat; it misunderstood or made facts up — rewrite the request with the missing data and permission to say “I don’t know”, and send it in a new chat; it is unclear what is needed — first ask for three questions and build a six-part prompt from the answers. Each path gives a new answer; if it misses again, the loop repeats"><defs><marker id="it-arv" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="rv-arh"/></marker><marker id="it-arvb" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" style="fill:var(--c-team)"/></marker></defs><rect class="rv-n bad" x="24" y="10" width="326" height="50" rx="7"/><path class="rv-x" d="M40,27 l16,16 M56,27 l-16,16"/><text class="rv-t" x="187" y="41" text-anchor="middle">Answer missed</text><text class="rv-run" x="24" y="86" text-anchor="start">1 · task understood</text><rect x="24" y="94" width="6" height="56" rx="2" style="fill:var(--c-chat)"/><rect class="rv-n req" x="24" y="94" width="326" height="56" rx="7"/><text class="rv-t" x="40" y="118" text-anchor="start">Refine in the same chat</text><text class="rv-q sm" x="40" y="138" text-anchor="start">“shorter”, “softer tone”</text><path class="rv-e " d="M187,150 L187,166" marker-end="url(#it-arv)"/><rect class="rv-n" x="24" y="168" width="326" height="40" rx="7"/><text class="rv-t sm" x="187" y="194" text-anchor="middle">New answer</text><text class="rv-run" x="24" y="236" text-anchor="start">2 · misread or made up</text><rect x="24" y="244" width="6" height="56" rx="2" style="fill:var(--c-proj)"/><rect class="rv-n req" x="24" y="244" width="326" height="56" rx="7"/><text class="rv-t" x="40" y="268" text-anchor="start">Rewrite the request</text><text class="rv-q sm" x="40" y="288" text-anchor="start">+ data, “I don’t know” ok</text><path class="rv-e " d="M187,300 L187,316" marker-end="url(#it-arv)"/><rect class="rv-n key" x="24" y="318" width="326" height="40" rx="7"/><text class="rv-t sm" x="187" y="344" text-anchor="middle">New chat</text><path class="rv-e " d="M187,358 L187,374" marker-end="url(#it-arv)"/><rect class="rv-n" x="24" y="376" width="326" height="40" rx="7"/><text class="rv-t sm" x="187" y="402" text-anchor="middle">New answer</text><text class="rv-run" x="24" y="444" text-anchor="start">3 · needs unclear</text><rect x="24" y="452" width="6" height="56" rx="2" style="fill:var(--c-code)"/><rect class="rv-n req" x="24" y="452" width="326" height="56" rx="7"/><text class="rv-t" x="40" y="476" text-anchor="start">First, 3 questions</text><text class="rv-q sm" x="40" y="496" text-anchor="start">questions → your answers</text><path class="rv-e " d="M187,508 L187,524" marker-end="url(#it-arv)"/><rect class="rv-n key" x="24" y="526" width="326" height="40" rx="7"/><text class="rv-t sm" x="187" y="552" text-anchor="middle">Prompt · 6 parts</text><path class="rv-e " d="M187,566 L187,582" marker-end="url(#it-arv)"/><rect class="rv-n" x="24" y="584" width="326" height="40" rx="7"/><text class="rv-t sm" x="187" y="610" text-anchor="middle">New answer</text><path class="rv-e " d="M187,624 L187,642" marker-end="url(#it-arv)"/><rect class="rv-n good" x="24" y="644" width="326" height="40" rx="7"/><path class="rv-ok big" d="M40,664 l7,7 l14,-15"/><text class="rv-t sm" x="187" y="670" text-anchor="middle">Fits</text><text class="rv-bl" x="187" y="710" text-anchor="middle">↺ missed again — next round</text><path class="rv-e back" d="M84,716 L84,728 L8,728 L8,35 L22,35" marker-end="url(#it-arvb)"/></svg></div><div class="sublabel" style="margin-top:22px">Path 3: three questions and a new request</div><div class="sublabel" style="margin-top:16px">Step 1</div><pre class="prompt">[task description]&#10;Before doing the task, ask me 3 questions whose answers would improve the result the most. Do not start the work until I answer.</pre><div class="sublabel" style="margin-top:12px">Step 3</div><pre class="prompt">Build a final prompt from the task and my answers: role, who and why, data, example, format, question at the end. Output only the prompt text.</pre><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Three situations and one action for each: refine in the same chat, redo the prompt, or get questions from the model first.</div><div class="fg"><span class="fk">In general</span>Refining keeps the context already given and fits when the task was understood. If the task was misread, redoing the prompt is faster. If the model made facts up, give it the needed data in the new request and allow it to say “I don’t know”<a class="proof" href="https://platform.claude.com/docs/en/test-and-evaluate/strengthen-guardrails/reduce-hallucinations" target="_blank" rel="noopener" data-quote="Anthropic: “Explicitly give Claude permission to admit uncertainty. This simple technique can drastically reduce false information” — platform.claude.com/docs/en/test-and-evaluate/strengthen-guardrails/reduce-hallucinations" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. The new answer is checked the same way, and the loop repeats until it fits. Questions from the model help when it is unclear what context is needed: ambiguity gives the model room to misinterpret<a class="proof" href="https://claude.com/blog/best-practices-for-prompt-engineering" target="_blank" rel="noopener" data-quote="Anthropic: “Don&#39;t assume the AI reads minds: Be specific about what you want. Leaving things ambiguous gives the AI room to misinterpret” — claude.com/blog/best-practices-for-prompt-engineering" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>, and when intent is unclear, models ask for clarification more often<a class="proof" href="https://developers.openai.com/api/docs/guides/prompt-guidance" target="_blank" rel="noopener" data-quote="OpenAI: “When the user&#39;s intent is unclear, the model is more likely to ask the user for clarification to proceed”; and “Before asking the user clarifying questions, you should complete the work that is already authorized from context” — developers.openai.com/api/docs/guides/prompt-guidance" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>For a new task where you are unsure of the context, start by asking for three questions. Send the final prompt built from the answers as a new request in a new chat.</div></div></section><section class="chapter" id="review"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.3-4.3"/></svg></span>Answer review: fix the original request</h2><p class="why">The “rewrite the request” path as an example: the review found gaps, the original request lost what was wrong and gained what was missing, and everything ran again.</p><div class="rv-wrap"><svg class="rv" viewBox="0 0 930 360" role="img" aria-label="First run: the request limits input to Russian numbers, agent, tests pass, review finds two gaps. The limit is removed from the original request, two cases are added, and the whole pipeline runs again: agent, tests and review, all covered."><title>First run: the request limits input to Russian numbers, agent, tests pass, review finds two gaps. The limit is removed from the original request, two cases are added, and the whole pipeline runs again: agent, tests and review, all covered.</title><defs><marker id="rv-ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="rv-arh"/></marker></defs><text class="rv-run" x="10" y="22" text-anchor="start">run 1</text><rect class="rv-n req" x="10" y="32" width="230" height="76" rx="7"/><text class="rv-k" x="26" y="54" text-anchor="start">Request v1</text><text class="rv-q" x="26" y="76" text-anchor="start">“Normalise phones”</text><text class="rv-q rv-lim" x="26" y="96" text-anchor="start">Russian numbers only</text><path class="rv-e " d="M240,61 L278,61" marker-end="url(#rv-ar)"/><rect class="rv-n key" x="280" y="32" width="110" height="58" rx="7"/><text class="rv-t" x="335" y="67" text-anchor="middle">Agent</text><path class="rv-e " d="M390,61 L428,61" marker-end="url(#rv-ar)"/><rect class="rv-n " x="430" y="32" width="120" height="58" rx="7"/><text class="rv-t" x="478" y="67" text-anchor="middle">Tests</text><path class="rv-ok" d="M516,61 l6,6 l12,-13"/><path class="rv-e " d="M550,61 L588,61" marker-end="url(#rv-ar)"/><rect class="rv-n sen" x="590" y="32" width="110" height="58" rx="7"/><text class="rv-t" x="645" y="67" text-anchor="middle">Review</text><path class="rv-e " d="M700,61 L738,61" marker-end="url(#rv-ar)"/><rect class="rv-n bad" x="740" y="32" width="180" height="58" rx="7"/><path class="rv-x" d="M760,51 l18,18 M778,51 l-18,18"/><text class="rv-t" x="850" y="67" text-anchor="middle">2 gaps</text><text class="rv-run" x="10" y="226" text-anchor="start">run 2 · the whole pipeline again</text><rect class="rv-n req v2" x="10" y="236" width="230" height="114" rx="7"/><text class="rv-k" x="26" y="258" text-anchor="start">Request v2</text><text class="rv-q" x="26" y="280" text-anchor="start">“Normalise phones”</text><text class="rv-del" x="26" y="300" text-anchor="start">− Russian numbers only</text><text class="rv-add" x="26" y="320" text-anchor="start">+ prefix without “+”</text><text class="rv-add" x="26" y="338" text-anchor="start">+ empty string</text><path class="rv-e " d="M240,265 L278,265" marker-end="url(#rv-ar)"/><rect class="rv-n key" x="280" y="236" width="110" height="58" rx="7"/><text class="rv-t" x="335" y="271" text-anchor="middle">Agent</text><path class="rv-e " d="M390,265 L428,265" marker-end="url(#rv-ar)"/><rect class="rv-n " x="430" y="236" width="120" height="58" rx="7"/><text class="rv-t" x="478" y="271" text-anchor="middle">Tests</text><path class="rv-ok" d="M516,265 l6,6 l12,-13"/><path class="rv-e " d="M550,265 L588,265" marker-end="url(#rv-ar)"/><rect class="rv-n sen" x="590" y="236" width="110" height="58" rx="7"/><text class="rv-t" x="645" y="271" text-anchor="middle">Review</text><path class="rv-e " d="M700,265 L738,265" marker-end="url(#rv-ar)"/><rect class="rv-n good" x="740" y="236" width="180" height="58" rx="7"/><path class="rv-ok big" d="M760,265 l8,8 l16,-17"/><text class="rv-t" x="850" y="271" text-anchor="middle">all covered</text><path class="rv-e back" d="M830,90 C 830,185 420,170 244,254" marker-end="url(#rv-ar)"/><text class="rv-bl" x="560" y="162" text-anchor="middle">fix the original request</text></svg><svg class="rv rv-v" viewBox="0 0 360 454" role="img" aria-label="First run: the request limits input to Russian numbers, agent, tests pass, review finds two gaps. The limit is removed from the original request, two cases are added, and the whole pipeline runs again: agent, tests and review, all covered."><defs><marker id="rv-arv" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="rv-arh"/></marker></defs><text class="rv-run" x="10" y="24" text-anchor="start">run 1</text><text class="rv-run" x="190" y="24" text-anchor="start">run 2</text><rect class="rv-n req" x="10" y="40" width="160" height="68" rx="7"/><text class="rv-k" x="20" y="57" text-anchor="start">Request v1</text><text class="rv-q sm" x="20" y="76" text-anchor="start">“Normalise phones”</text><text class="rv-q sm rv-lim" x="20" y="96" text-anchor="start">Russian numbers only</text><path class="rv-e " d="M90,108 L90,128" marker-end="url(#rv-arv)"/><rect class="rv-n key" x="10" y="130" width="160" height="44" rx="7"/><text class="rv-t" x="90" y="158" text-anchor="middle">Agent</text><path class="rv-e " d="M90,174 L90,194" marker-end="url(#rv-arv)"/><rect class="rv-n " x="10" y="196" width="160" height="44" rx="7"/><text class="rv-t" x="90" y="224" text-anchor="middle">Tests</text><path class="rv-ok" d="M136,218 l5,5 l10,-11"/><path class="rv-e " d="M90,240 L90,260" marker-end="url(#rv-arv)"/><rect class="rv-n sen" x="10" y="262" width="160" height="44" rx="7"/><text class="rv-t" x="90" y="290" text-anchor="middle">Review</text><path class="rv-e " d="M90,306 L90,326" marker-end="url(#rv-arv)"/><rect class="rv-n bad" x="10" y="328" width="160" height="50" rx="7"/><path class="rv-x" d="M24,344 l16,16 M40,344 l-16,16"/><text class="rv-t" x="104" y="359" text-anchor="middle">2 gaps</text><rect class="rv-n req v2" x="190" y="40" width="160" height="104" rx="7"/><text class="rv-k" x="200" y="57" text-anchor="start">Request v2</text><text class="rv-q sm" x="200" y="76" text-anchor="start">“Normalise phones”</text><text class="rv-del sm" x="200" y="96" text-anchor="start">− Russian numbers only</text><text class="rv-add sm" x="200" y="114" text-anchor="start">+ prefix without “+”</text><text class="rv-add sm" x="200" y="132" text-anchor="start">+ empty string</text><path class="rv-e " d="M270,144 L270,164" marker-end="url(#rv-arv)"/><rect class="rv-n key" x="190" y="166" width="160" height="44" rx="7"/><text class="rv-t" x="270" y="194" text-anchor="middle">Agent</text><path class="rv-e " d="M270,210 L270,230" marker-end="url(#rv-arv)"/><rect class="rv-n " x="190" y="232" width="160" height="44" rx="7"/><text class="rv-t" x="270" y="260" text-anchor="middle">Tests</text><path class="rv-ok" d="M316,254 l5,5 l10,-11"/><path class="rv-e " d="M270,276 L270,296" marker-end="url(#rv-arv)"/><rect class="rv-n sen" x="190" y="298" width="160" height="44" rx="7"/><text class="rv-t" x="270" y="326" text-anchor="middle">Review</text><path class="rv-e " d="M270,342 L270,362" marker-end="url(#rv-arv)"/><rect class="rv-n good" x="190" y="364" width="160" height="50" rx="7"/><path class="rv-ok big" d="M204,389 l7,7 l14,-15"/><text class="rv-t" x="284" y="395" text-anchor="middle">all covered</text><path class="rv-e back" d="M90,378 C 90,402 180,402 180,130 C 180,90 185,80 188,72" marker-end="url(#rv-arv)"/><text class="rv-bl sm" x="10" y="444" text-anchor="start">↺ fix the original request</text></svg></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The review found two cases that were not in the task: an international prefix without a plus and an empty string. The needless “Russian numbers only” limit was removed from the original request, the two cases were added, and the whole pipeline ran again.</div><div class="fg"><span class="fk">In general</span>A gap the review finds goes into the original request, and the cycle starts over: the agent writes the code again, tests and review check the new cases, and the clarification stays in the task for future runs. A separate review pass with its own instruction is described in Google’s prompting guide<a class="proof" href="https://www.kaggle.com/whitepaper-prompt-engineering" target="_blank" rel="noopener" data-quote="Google, Prompt Engineering whitepaper: the code section, including review and debugging as a separate prompt — kaggle.com/whitepaper-prompt-engineering" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>When the review finds something, add it to the original request and rerun the whole cycle: change, tests, review.</div></div><a class="hdd-cta" href="/en/blog/harness-driven-development/"><span class="hdd-k">Next step · HDD</span><b>Harness-Driven Development</b><span>How to move a gap that keeps coming back from the request into the harness rules</span></a></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/specs-rules-skills/"><div class="k">Context</div><div class="t">Specs, bible, rules and skills</div><div class="d">What an agent should know about a project</div></a><a href="/en/blog/harness-driven-development/"><div class="k">Method</div><div class="t">Harness-Driven Development</div><div class="d">Agent error → environment rule</div></a><a href="/en/blog/work-prompts-examples/"><div class="k">Practice</div><div class="t">Prompts for work tasks</div><div class="d">Five parts and six examples</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Comparison</div><div class="t">Comparing harnesses</div><div class="d">Claude Code, Codex, Cursor, Hermes and chat</div></a></div></section><footer>Techniques follow the official Anthropic, OpenAI and Google guides; the source is behind the icon next to each claim. Quotes from Google’s guide are paraphrased.</footer></div>]]></content:encoded></item>
<item><title>A reconcile loop for specs: like Kubernetes, with the spec as desired state and code as actual</title><link>https://www.urvanov.com/en/blog/spec-reconcile-loop/</link><guid>https://www.urvanov.com/en/blog/spec-reconcile-loop/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>Spec-driven development with a reconcile loop: who changes the desired state and who brings the code to it, why green tests do not yet mean “correct”, and which six environment capabilities the agent needs to close the loop.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-rec-en"><div class="hc" role="img" aria-label="The reconcile chain: desired is the spec, the actor is the agent, actual is the code, the measure is tests"><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg><b>Desired</b><code>spec</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="8" width="14" height="11" rx="3"/><path d="M12 4v4M9 13h.01M15 13h.01M9 16h6"/></svg><b>Actor</b><code>agent</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 7l-5 5 5 5M16 7l5 5-5 5M14 4l-4 16"/></svg><b>Actual</b><code>code</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 16a8 8 0 1 1 16 0"/><path d="M12 16l4-5"/><path d="M4 20h16"/></svg><b>Measure</b><code>tests</code></div></div><section class="chapter" id="k8s"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2.5"/><path d="M12 4v5.5M12 14.5V20M4 12h5.5M14.5 12H20M6.3 6.3l3.9 3.9M13.8 13.8l3.9 3.9M17.7 6.3l-3.9 3.9M10.2 13.8l-3.9 3.9"/></svg></span>The same loop as in Kubernetes</h2><p class="why">The desired state here is the <a href="/en/blog/specs-by-aggregates/">aggregate dictionary</a>: one entry per concept, requirements marked MUST and SHOULD.</p><div class="kl" role="img" aria-label="Kubernetes: chart, controller, nodes, probes. Specs: dictionary, agent, code, tests. A human changes only the desired state, and the actor keeps reconciling the measurement with it."><div class="kl-hu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg>a human changes the desired state <span aria-hidden="true">↓</span></div><div class="kl-g"><div class="kl-c"></div><div class="kl-h">desired</div><div class="kl-h">actor</div><div class="kl-h">actual</div><div class="kl-h">measure</div><div class="kl-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2.5"/><path d="M12 4v5.5M12 14.5V20M4 12h5.5M14.5 12H20M6.3 6.3l3.9 3.9M13.8 13.8l3.9 3.9M17.7 6.3l-3.9 3.9M10.2 13.8l-3.9 3.9"/></svg><b>Kubernetes</b></div><div class="kl-x on"><small class="kl-m">desired</small>chart · manifest</div><div class="kl-x"><small class="kl-m">actor</small>controller</div><div class="kl-x"><small class="kl-m">actual</small>nodes · pods</div><div class="kl-x"><small class="kl-m">measure</small>probes · metrics</div><div class="kl-r"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg><b>Specs</b></div><div class="kl-x on"><small class="kl-m">desired</small>dictionary · MUST</div><div class="kl-x"><small class="kl-m">actor</small>agent</div><div class="kl-x"><small class="kl-m">actual</small>code</div><div class="kl-x"><small class="kl-m">measure</small>tests · quality</div></div><div class="kl-bk"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 0 1-15.5 6.3"/><path d="M3 12a9 9 0 0 1 15.5-6.3"/><path d="M18 2v4h-4M6 22v-4h4"/></svg>measure → actor, round and round</div></div><p class="cap">The reconcile loop follows the <a href="https://kubernetes.io/docs/concepts/architecture/controller/" target="_blank" rel="noopener">Kubernetes docs on controllers</a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>In Kubernetes a human edits the chart and the controller brings the nodes to it. Here a human edits the dictionary and the agent brings the code to it and checks with tests.</div><div class="fg"><span class="fk">In general</span>Both systems keep the desired state apart from the actual one and reconcile them in a loop. The human in the loop changes only the desired state, so every edit immediately becomes work for the actor.</div><div class="fa"><span class="fk">Next step</span>Edit the requirement in the dictionary instead of fixing code by hand, and run the agent with the task of bringing the code in line with the dictionary.</div></div></section><section class="chapter" id="sensors"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 16a8 8 0 1 1 16 0"/><path d="M12 16l4-5"/><path d="M4 20h16"/></svg></span>A check sees only what was put into it</h2><p class="why">The example is the meeting room booking from <a href="/en/blog/specs-by-aggregates/">Specs by aggregate</a>: three MUST requirements and one SHOULD.</p><div class="sn"><div class="sn-p"><div class="sn-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2.5"/><path d="M12 4v5.5M12 14.5V20M4 12h5.5M14.5 12H20M6.3 6.3l3.9 3.9M13.8 13.8l3.9 3.9M17.7 6.3l-3.9 3.9M10.2 13.8l-3.9 3.9"/></svg><b>Kubernetes</b></div><div class="sn-i ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg><code>/healthz → 200</code></div><div class="sn-i no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg><code>order queue is stuck</code></div><div class="sn-v">probe is green, service is down</div></div><div class="sn-p"><div class="sn-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5"/></svg><b>Specs</b></div><div class="sn-i ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg><code>MUST · no overlap</code><span>test</span></div><div class="sn-i ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg><code>MUST · forward only</code><span>test</span></div><div class="sn-i no"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg><code>MUST · 15 min → closed</code><span>no check</span></div><div class="sn-i eye"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg><code>SHOULD · channel</code><span>review</span></div><div class="sn-cov"><span>MUST covered</span><span class="sn-bar"><i style="width:67%"></i></span><b>2 / 3</b></div><div class="sn-v">tests are green, one MUST is unchecked</div></div></div><div class="sn-rules"><span class="chip">every MUST → its own check</span><span class="chip">MUST without a check = finding</span><span class="chip">green ≠ correct</span></div><p class="cap">Which probes exist and what they check: <a href="https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/" target="_blank" rel="noopener">Kubernetes: probes</a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The probe answers “200” while orders are stuck, and the booking tests are green while nobody checks the 15-minute rule.</div><div class="fg"><span class="fk">In general</span>A check confirms only what is written into it and says nothing about the rest. So the aggregate card is compared against the checks: a MUST without a check is a gap, not a met requirement.</div><div class="fa"><span class="fk">Next step</span>Go through the MUSTs in your dictionary and mark the ones without a test. Turn each into a task, or deliberately downgrade it to SHOULD.</div></div></section><section class="chapter" id="env"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/><path d="M8 21h8"/></svg></span>The environment decides whether the loop closes</h2><div class="ev-pair"><div class="ev-pp"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2.5"/><path d="M12 4v5.5M12 14.5V20M4 12h5.5M14.5 12H20M6.3 6.3l3.9 3.9M13.8 13.8l3.9 3.9M17.7 6.3l-3.9 3.9M10.2 13.8l-3.9 3.9"/></svg><b>cluster</b><small>the controller’s environment</small></div><span class="ev-eq">≈</span><div class="ev-pp"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/><path d="M8 21h8"/></svg><b>harness</b><small>the agent’s environment</small></div></div><div class="ev"><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 4l12 8-12 8z"/></svg></span><b>Run code</b><small><span>without it →</span> guesses instead of facts</small></div><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.7 3h10.6a2 2 0 0 0 1.7-3l-5-9V3"/></svg></span><b>Tests</b><small><span>without it →</span> MUST cannot be checked</small></div><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16M4 10h16M4 15h10M4 20h7"/></svg></span><b>Logs</b><small><span>without it →</span> no way to see what broke</small></div><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg></span><b>Test data</b><small><span>without it →</span> checks on empty tables</small></div><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3v5M15 3v5M6 8h12v3a6 6 0 0 1-12 0z"/><path d="M12 17v4"/></svg></span><b>Services via MCP</b><small><span>without it →</span> integrations in the dark</small></div><div class="ev-c"><span class="ev-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/><path d="M9 12l2 2 4-4"/></svg></span><b>Sandbox and permissions</b><small><span>without it →</span> too risky to let it act</small></div></div><a class="ev-cta" href="/en/blog/ai-in-code-harness-and-tools/"><span class="ev-ci"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/><path d="M8 21h8"/></svg></span><span class="ev-ct"><small>Separate article</small><b>Choosing the environment: a harness comparison</b><span>Claude Code, Codex, Cursor, Hermes and chat on one map</span></span><span class="ev-ca"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span></a><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The Kubernetes controller works because the cluster gives it an API, nodes and probes. For the same loop the agent needs to run code, tests, logs, data, services and a sandbox.</div><div class="fg"><span class="fk">In general</span>The dictionary sets the desired state, but only someone who can run and measure the code can reconcile it with that state. Whatever the environment lacks, the agent cannot check, and the loop stays open at that point.</div><div class="fa"><span class="fk">Next step</span>Mark which of the six capabilities your agent has. For each missing one, decide whether to add it to the harness or switch harnesses.</div></div></section><section class="chapter" id="next"><h2>Read next</h2><div class="links three"><a href="/en/blog/specs-by-aggregates/"><div class="k">Desired state</div><div class="t">Specs by aggregate</div><div class="d">dictionary, RFC requirements and contexts</div></a><a href="/en/blog/harness-driven-development/"><div class="k">Mistake loop</div><div class="t">Harness-Driven Development</div><div class="d">how agent mistakes become rules</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Environment</div><div class="t">Harness comparison</div><div class="d">where the agent works and what it sees</div></a></div></section><footer>The booking example is made up. Terms and approaches follow the sources linked under the diagrams.</footer></div>]]></content:encoded></item>
<item><title>Specs by aggregate: RFC requirements and bounded contexts instead of a spec per feature</title><link>https://www.urvanov.com/en/blog/specs-by-aggregates/</link><guid>https://www.urvanov.com/en/blog/specs-by-aggregates/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>Spec-driven development without spec sprawl: how to keep specs in one aggregate dictionary so they do not multiply with every feature: requirement levels, the aggregate card and context boundaries.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-agg-en"><div class="hc" role="img" aria-label="Chain: bounded context, aggregate, MUST-level invariant, check"><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/><path d="M11 7h4a2 2 0 0 1 2 2v4"/></svg><b>Context</b><code>booking</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9z"/><path d="M12 12l8-4.5M12 12v9M12 12L4 7.5"/></svg><b>Aggregate</b><code>Reservation</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h6"/><path d="M17 15l2 2 3-4"/></svg><b>Invariant</b><code>MUST</code></div><span class="hc-a" aria-hidden="true">→</span><div class="hc-s"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.7 3h10.6a2 2 0 0 0 1.7-3l-5-9V3"/></svg><b>Check</b><code>test</code></div></div><section class="chapter" id="growth"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 20h18"/><path d="M6 16v-3M10 16V9M14 16v-6M18 16V5"/></svg></span>Why specs pile up</h2><div class="gw"><div class="gw-p"><div class="gw-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><b>Spec per feature</b><small>a concept is described in every feature</small></div><div class="gw-files"><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class=""><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class=""><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class=""><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class=""><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class="on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i><i class=""><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg></i></div><div class="gw-n"><b>12 files</b><span class="warn">“Booking” in 7</span></div><span class="gw-c bad">grows with features</span></div><div class="gw-p on"><div class="gw-h"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9z"/><path d="M12 12l8-4.5M12 12v9M12 12L4 7.5"/></svg><b>Aggregate dictionary</b><small>a concept is described once</small></div><div class="gw-aggs"><div class="gw-ag"><code>Reservation</code><span class="gw-d"><i></i><i></i><i></i><i></i><i></i></span></div><div class="gw-ag"><code>Room</code><span class="gw-d"><i></i><i></i><i></i></span></div><div class="gw-ag"><code>TimeSlot</code><span class="gw-d"><i></i><i></i></span></div><div class="gw-ag"><code>Member</code><span class="gw-d"><i></i><i></i></span></div></div><div class="gw-n"><b>4 entries</b><span class="good">“Booking” in 1</span></div><span class="gw-c good">grows with the domain</span></div></div><div class="gw-flow"><span class="gw-fs"><code>Feature 13</code></span><span class="gw-ar">→</span><span class="gw-fs"><code>[booking::Reservation]</code><em>+1 MUST</em></span><span class="gw-ar">→</span><span class="gw-fs"><code>test</code><em>+1</em></span></div><p class="cap">Numbers are illustrative. How <a href="https://github.com/Fission-AI/OpenSpec" target="_blank" rel="noopener">OpenSpec</a> lays out specs and changes: specs/ and changes/ folders, finished changes go to an archive.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Twelve features produced twelve specs, and booking is described in seven of them, each a little differently. In the dictionary the same features added lines to four aggregate entries.</div><div class="fg"><span class="fk">In general</span>When a spec is tied to a change or a feature, every task adds files, and one concept drifts across several places. When the unit is an aggregate, the number of entries is bounded by the domain itself, and a feature only adds requirements to an entry.</div><div class="fa"><span class="fk">Next step</span>List the concepts that appear in three or more specs and give each one a single dictionary entry. Let feature specs link to the entry instead of retelling it.</div></div></section><section class="chapter" id="rfc"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h6"/><path d="M17 15l2 2 3-4"/></svg></span>RFC 2119 requirement levels</h2><div class="rl"><div class="rl-r rl-th"><span>Word</span><span>Meaning</span><span>Strength</span><span>Check</span></div><div class="rl-r s5"><code class="rl-k">MUST</code><span class="rl-m">required</span><span class="rl-b"><i style="width:100%"></i></span><span class="rl-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.7 3h10.6a2 2 0 0 0 1.7-3l-5-9V3"/></svg>automated test<small>blocks</small></span></div><div class="rl-r s5"><code class="rl-k">MUST NOT</code><span class="rl-m">forbidden</span><span class="rl-b"><i style="width:100%"></i></span><span class="rl-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.7 3h10.6a2 2 0 0 0 1.7-3l-5-9V3"/></svg>automated test<small>blocks</small></span></div><div class="rl-r s3"><code class="rl-k">SHOULD</code><span class="rl-m">default, deviate with a reason</span><span class="rl-b"><i style="width:60%"></i></span><span class="rl-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>review<small>warns</small></span></div><div class="rl-r s1"><code class="rl-k">MAY</code><span class="rl-m">allowed</span><span class="rl-b"><i style="width:20%"></i></span><span class="rl-c"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>none<small>not checked</small></span></div></div><div class="rl-syn"><span class="chip">MUST = SHALL</span></div><p class="cap">Words and meanings follow <a href="https://www.rfc-editor.org/rfc/rfc2119" target="_blank" rel="noopener">RFC 2119</a>. Each word maps to its own kind of check.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>In the booking entry, “intervals do not overlap” is a MUST checked by a test, and “confirmation goes to the same channel” is a SHOULD looked at in review.</div><div class="fg"><span class="fk">In general</span>The requirement word tells you right away how to check it and what to do on a violation. The agent reads MUST as a boundary and SHOULD as a default and does not mix them up.</div><div class="fa"><span class="fk">Next step</span>Rewrite the requirements in your spec with these four words and put the test that checks it next to every MUST.</div></div></section><section class="chapter" id="card"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9h10M7 13h6M7 17h8"/></svg></span>The aggregate card</h2><div class="ag" role="img" aria-label="Example entry for the Reservation aggregate in the booking context: address, invariants, commands, access, links and the feature spec"><div class="ag-r"><pre class="ag-c">## [booking::Reservation]&#10;Class: aggregate&#10;Description: A meeting room booked for an interval.</pre><div class="ag-n"><span class="nb">1</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M7 10h4M7 14h6M16 10v4"/></svg><span>address: context::name</span></div></div><div class="ag-r"><pre class="ag-c">Invariants:&#10;  - MUST: active bookings of a room never overlap&#10;  - MUST: held → confirmed → closed, forward only&#10;  - MUST: held unconfirmed for 15 min → closed&#10;  - SHOULD: confirm in the channel it was made in</pre><div class="ag-n"><span class="nb">2</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h6"/><path d="M17 15l2 2 3-4"/></svg><span>requirements → checks</span></div></div><div class="ag-r"><pre class="ag-c">Commands: HoldRoom, ConfirmReservation,&#10;          CancelReservation</pre><div class="ag-n"><span class="nb">3</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 4l12 8-12 8z"/></svg><span>the only way to change it</span></div></div><div class="ag-r"><pre class="ag-c">Access:&#10;  CanHoldRoom: [booking::Role::Member]&#10;  CanCancelReservation: Member (own), Admin</pre><div class="ag-n"><span class="nb">4</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg><span>who may</span></div></div><div class="ag-r"><pre class="ag-c">Depends on: [[booking::Room]], [[booking::TimeSlot]]</pre><div class="ag-n"><span class="nb">5</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/></svg><span>links by id</span></div></div><div class="ag-r"><pre class="ag-c">Spec: [[room-booking]]</pre><div class="ag-n"><span class="nb">6</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><span>which feature it came from</span></div></div></div><p class="cap">The example is made up. Terms follow <a href="https://martinfowler.com/bliki/DDD_Aggregate.html" target="_blank" rel="noopener">Martin Fowler: DDD Aggregate</a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The whole booking is one card: an address, four requirements, three commands, permissions, links and the feature it came from.</div><div class="fg"><span class="fk">In general</span>An aggregate is a boundary inside which the requirements always hold, and it can change only through its own commands. That is why the card keeps the rules next to the only ways to break them.</div><div class="fa"><span class="fk">Next step</span>Give every aggregate a six-field card. If a requirement cannot be assigned to any aggregate, the aggregate most likely has not been named yet.</div></div></section><section class="chapter" id="contexts"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/><path d="M11 7h4a2 2 0 0 1 2 2v4"/></svg></span>Bounded contexts</h2><div class="cx"><div class="cx-b"><div class="cx-t"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/><path d="M11 7h4a2 2 0 0 1 2 2v4"/></svg><code>booking</code></div><div class="cx-a"><span class="chip">Reservation</span><span class="chip">Room</span><span class="chip">TimeSlot</span></div></div><div class="cx-b"><div class="cx-t"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/><path d="M11 7h4a2 2 0 0 1 2 2v4"/></svg><code>billing</code></div><div class="cx-a"><span class="chip">Invoice</span><span class="chip">Tariff</span></div></div><div class="cx-b"><div class="cx-t"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/><path d="M11 7h4a2 2 0 0 1 2 2v4"/></svg><code>access</code></div><div class="cx-a"><span class="chip">Pass</span><span class="chip">Level</span></div></div></div><div class="cx-ls"><small><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/></svg>links between contexts go by id only</small><span class="cx-l"><code>billing::Invoice</code><span class="cx-ar">→ id →</span><code>booking::Reservation</code></span><span class="cx-l"><code>access::Pass</code><span class="cx-ar">→ id →</span><code>booking::Reservation</code></span></div><div class="cx-w"><div class="cx-wq">“Level”</div><div class="cx-ws"><div><code>booking::Room.floor</code><span class="chip">Floor</span></div><div><code>access::Level</code><span class="chip">Clearance</span></div></div><small>one word, two terms, different labels</small></div><div class="cx-rules"><span class="cx-rl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M7 10h4M7 14h6M16 10v4"/></svg>one term = one entry</span><span class="cx-rl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/></svg>link as [[ctx::Name]]</span><span class="cx-rl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v6M12 9l-6 6v6M12 9l6 6v6"/></svg>same word → separate entries</span><span class="cx-rl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 0 1-15.5 6.3"/><path d="M3 12a9 9 0 0 1 15.5-6.3"/><path d="M18 2v4h-4M6 22v-4h4"/></svg>dictionary changes with the spec</span></div><p class="cap">The approach is <a href="https://martinfowler.com/bliki/BoundedContext.html" target="_blank" rel="noopener">Bounded Context</a> and <a href="https://martinfowler.com/bliki/UbiquitousLanguage.html" target="_blank" rel="noopener">Ubiquitous Language</a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The invoice and the pass refer to a booking by id and know nothing about its insides. “Level” means a floor in booking and a clearance in access, and these are two separate entries.</div><div class="fg"><span class="fk">In general</span>A context is an area where every word has one meaning. When a word appears in two contexts, you create two terms with different labels; otherwise the agent carries a rule from one into the other.</div><div class="fa"><span class="fk">Next step</span>Sort your aggregates into contexts and find the words that appear in two of them. Give each such word separate entries and different labels in the interface.</div></div></section><section class="chapter" id="next"><h2>Read next</h2><a class="ev-cta" href="/en/blog/spec-reconcile-loop/"><span class="ev-ci"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="2.5"/><path d="M12 4v5.5M12 14.5V20M4 12h5.5M14.5 12H20M6.3 6.3l3.9 3.9M13.8 13.8l3.9 3.9M17.7 6.3l-3.9 3.9M10.2 13.8l-3.9 3.9"/></svg></span><span class="ev-ct"><small>Continued</small><b>A reconcile loop for specs</b><span>like Kubernetes: desired state, checks and the agent’s environment</span></span><span class="ev-ca"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span></a><div class="links three"><a href="/en/blog/harness-driven-development/"><div class="k">Mistake loop</div><div class="t">Harness-Driven Development</div><div class="d">how agent mistakes become rules</div></a><a href="/en/blog/specs-rules-skills/"><div class="k">Context</div><div class="t">Specs, bible, rules and skills</div><div class="d">what the agent knows about the project and where it lives</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Environment</div><div class="t">Harness comparison</div><div class="d">where the agent works and what it sees</div></a></div></section><footer>The booking example is made up. Terms and approaches follow the sources linked under the diagrams.</footer></div>]]></content:encoded></item>
<item><title>AGENTS.md and CLAUDE.md, specs, rules and skills: what an agent should know about a project and where to keep it</title><link>https://www.urvanov.com/en/blog/specs-rules-skills/</link><guid>https://www.urvanov.com/en/blog/specs-rules-skills/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>Four kinds of persistent context for AI (AGENTS.md, CLAUDE.md, skills): the task spec, the project bible, rules and skills. What goes into each, when it enters the context, and what ChatGPT and Claude offer. Based on Anthropic, OpenAI, GitHub, Cursor and Cline docs.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-prompts-en"><div class="ly"><div class="ly-c" style="--c:var(--c-code)"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h4"/></svg></span><b>Spec</b><small>what to build in one task</small><span class="ly-w">for one task</span></div><div class="ly-c" style="--c:var(--c-proj)"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3z"/><path d="M5 17a3 3 0 0 1 3-3h11M12 7v4M10 9h4"/></svg></span><b>Bible</b><small>what the product is</small><span class="ly-w">at task start</span></div><div class="ly-c" style="--c:var(--c-chat)"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/><path d="M18 16l2 2-2 2"/></svg></span><b>Rules</b><small>how to work in the project</small><span class="ly-w">every session</span></div><div class="ly-c" style="--c:var(--c-work)"><span class="ly-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg></span><b>Skill</b><small>how to run a procedure</small><span class="ly-w">on call</span></div></div><p class="cap">A model does not remember a project between sessions<a class="proof" href="https://cursor.com/docs/context/rules" target="_blank" rel="noopener" data-quote="Cursor: «Large language models don&#x27;t retain memory between completions. Rules provide persistent, reusable context at the prompt level» — cursor.com/docs/context/rules" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. Four kinds of files give that context back.</p><section class="chapter" id="map"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18M9 9v11"/></svg></span>Four layers of context</h2><div class="tbl l4"><table><thead><tr><th>Layer</th><th>What goes in</th><th>When in context</th><th>Files</th></tr></thead><tbody><tr><td><span class="ly-t" style="--c:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h4"/></svg>Spec</span></td><td>requirements, plan, steps of one task</td><td>for one task</td><td><code>spec.md · plan.md · tasks.md</code></td></tr><tr><td><span class="ly-t" style="--c:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3z"/><path d="M5 17a3 3 0 0 1 3-3h11M12 7v4M10 9h4"/></svg>Bible</span></td><td>product goal, users, decisions</td><td>at task start</td><td><code>projectbrief.md · productContext.md</code></td></tr><tr><td><span class="ly-t" style="--c:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/><path d="M18 16l2 2-2 2"/></svg>Rules</span></td><td>commands, style, prohibitions</td><td>every session</td><td><code>CLAUDE.md · AGENTS.md · .cursor/rules</code></td></tr><tr><td><span class="ly-t" style="--c:var(--c-work)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>Skill</span></td><td>procedure with examples and scripts</td><td>description always, body on call</td><td><code>SKILL.md</code></td></tr></tbody></table></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The layers differ in lifetime and in when they enter the context.</div><div class="fg"><span class="fk">In general</span>Rules load into every session, so they are kept short: Anthropic recommends under 200 lines per file<a class="proof" href="https://code.claude.com/docs/en/memory" target="_blank" rel="noopener" data-quote="Anthropic: «Size: target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence» — code.claude.com/docs/en/memory" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. Long and rarely used content moves into skills, whose body loads only on call<a class="proof" href="https://code.claude.com/docs/en/skills" target="_blank" rel="noopener" data-quote="Anthropic: «skill descriptions are loaded into context so Claude knows what&#x27;s available, but full skill content only loads when invoked» — code.claude.com/docs/en/skills" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Go through your instructions file: keep facts in the rules, move procedures into skills and the product description into the bible.</div></div></section><section class="chapter" id="spec"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h4"/></svg></span>Spec: one task before the code</h2><p class="why">A spec describes the task before work starts: first what and why, then how<a class="proof" href="https://github.com/github/spec-kit" target="_blank" rel="noopener" data-quote="GitHub Spec Kit: «Define what and why before deciding how to build it. SDD turns your requirements into a specification, a technical plan, and actionable tasks, then guides implementation against those artifacts» — github.com/github/spec-kit" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="seq"><div class="sq"><span class="sq-n">1</span><b>Principles</b><small>once per project</small></div><span class="sq-a">→</span><div class="sq"><span class="sq-n">2</span><b>Spec</b><small>what and why</small></div><span class="sq-a">→</span><div class="sq"><span class="sq-n">3</span><b>Plan</b><small>how</small></div><span class="sq-a">→</span><div class="sq"><span class="sq-n">4</span><b>Tasks</b><small>steps</small></div><span class="sq-a">→</span><div class="sq"><span class="sq-n">5</span><b>Implement</b><small>code step by step</small></div></div><p class="cap">Main steps of GitHub Spec Kit<a class="proof" href="https://github.com/github/spec-kit" target="_blank" rel="noopener" data-quote="GitHub Spec Kit: constitution создаётся один раз на проект — «Create principles focused on code quality, testing, and maintainability». Пересказ — github.com/github/spec-kit" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. How to split a large spec into parts: <a href="/en/blog/specs-by-aggregates/">Specs by aggregates</a></p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Spec Kit takes a task from project principles through the spec and plan to steps and code.</div><div class="fg"><span class="fk">In general</span>Requirements are written before the code, and the review checks the result against that text. How a spec fits into the harness is covered in <a href="/en/blog/harness-driven-development/#spec">HDD and specs</a>.</div><div class="fa"><span class="fk">Next step</span>For a task longer than a day, write a spec: what, why and how you will know it is done.</div></div></section><section class="chapter" id="bible"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3z"/><path d="M5 17a3 3 0 0 1 3-3h11M12 7v4M10 9h4"/></svg></span>Project bible: what the product is</h2><p class="why">The bible is a standing description of the product: why it exists, who it serves, how it works and what has been decided. The term comes from practice; the closest documented analogue is Cline’s Memory Bank<a class="proof" href="https://docs.cline.bot/prompting/cline-memory-bank" target="_blank" rel="noopener" data-quote="Cline: Memory Bank — «a documentation methodology that transforms Cline from a stateless assistant into a persistent development partner. Through structured markdown files, Cline can &#x27;remember&#x27; your project details across sessions» — docs.cline.bot/prompting/cline-memory-bank" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="fls"><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>projectbrief.md</code><small>goals and requirements</small></div><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>productContext.md</code><small>why it exists, what it solves</small></div><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>systemPatterns.md</code><small>architecture and patterns</small></div><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>techContext.md</code><small>stack and constraints</small></div><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>activeContext.md</code><small>current focus and next steps</small></div><div class="fl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/></svg><code>progress.md</code><small>what works, what is left</small></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Six Memory Bank files: from the product goal to current progress.</div><div class="fg"><span class="fk">In general</span>The bible answers the questions otherwise asked in every new chat: what the product is, which decisions were made, what is in progress. The current-context file changes most often<a class="proof" href="https://docs.cline.bot/prompting/cline-memory-bank" target="_blank" rel="noopener" data-quote="Cline: activeContext.md — текущий фокус, последние изменения и следующие шаги, обновляется чаще остальных. Пересказ — docs.cline.bot/prompting/cline-memory-bank" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Start with one file: product goal, users, key terms and recent decisions with dates.</div></div></section><section class="chapter" id="rules"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/><path d="M18 16l2 2-2 2"/></svg></span>Rules: in every session</h2><p class="why">Rules are instructions the harness puts at the start of every session<a class="proof" href="https://code.claude.com/docs/en/memory" target="_blank" rel="noopener" data-quote="Anthropic: «CLAUDE.md files are loaded into the context window at the start of every session» — code.claude.com/docs/en/memory" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="io"><div><div class="k fn">CLAUDE.md</div><div class="v">Claude Code, path-scoped rules in <code>.claude/rules/</code><a class="proof" href="https://code.claude.com/docs/en/memory" target="_blank" rel="noopener" data-quote="Anthropic: «Rules can also be scoped to specific file paths, so they only load into context when Claude works with matching files» — code.claude.com/docs/en/memory" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div><div class="k fn">AGENTS.md</div><div class="v">“A README for agents”: Codex, Cursor, Gemini CLI, Copilot and others<a class="proof" href="https://agents.md/" target="_blank" rel="noopener" data-quote="agents.md: «Think of AGENTS.md as a README for agents: a dedicated, predictable place to provide the context and instructions to help AI coding agents work on your project» — agents.md" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div><div class="k fn">.cursor/rules</div><div class="v">Cursor, four ways to apply<a class="proof" href="https://cursor.com/docs/context/rules" target="_blank" rel="noopener" data-quote="Cursor: четыре режима — Always Apply, Apply Intelligently, Apply to Specific Files, Apply Manually — cursor.com/docs/context/rules" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div></div><div class="sublabel" style="margin-top:18px">When a rule enters the context · Cursor</div><div class="mds"><div class="md"><b>Always</b><small>every chat</small></div><div class="md"><b>By description</b><small>the agent decides</small></div><div class="md"><b>By files</b><small>path pattern matches</small></div><div class="md"><b>Manually</b><small>@rule</small></div></div><div class="mt"><b>≤ 200</b><span>lines per CLAUDE.md file<a class="proof" href="https://code.claude.com/docs/en/memory" target="_blank" rel="noopener" data-quote="Anthropic: «Size: target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence» — code.claude.com/docs/en/memory" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Three formats of one idea: an instructions file the harness reads at the start.</div><div class="fg"><span class="fk">In general</span>Rules stay context, and the model can break them; an action that must never happen is blocked with a hook. The more specific and concise a rule, the more consistently it is followed<a class="proof" href="https://code.claude.com/docs/en/memory" target="_blank" rel="noopener" data-quote="Anthropic: «Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead. The more specific and concise your instructions, the more consistently Claude follows them» — code.claude.com/docs/en/memory" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Create AGENTS.md or CLAUDE.md: build and test commands, code style, prohibitions. Move folder-specific rules into path-scoped rules.</div></div></section><section class="chapter" id="skills"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg></span>Skills: a procedure on call</h2><p class="why">A skill is a folder with a SKILL.md instruction, examples and scripts for a recurring procedure<a class="proof" href="https://learn.chatgpt.com/docs/build-skills" target="_blank" rel="noopener" data-quote="OpenAI: «ChatGPT and Codex start with each skill&#x27;s name and description, then load the full SKILL.md instructions when they decide to use that skill» — learn.chatgpt.com/docs/build-skills" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="pl"><div class="pl-r"><span class="pl-k">Session start</span><div class="pl-cs"><span class="pl-c">report</span><span class="pl-c on">PR review</span><span class="pl-c">release</span><span class="pl-c">client email</span></div><span class="pl-s">name + description</span></div><div class="pl-d">↓ the agent picked “PR review”</div><div class="pl-r"><span class="pl-k">On call</span><div class="pl-x"><code>SKILL.md</code><span>instructions, examples, scripts</span></div><span class="pl-s">full body</span></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Descriptions of all skills are always in context; the body loads once one is picked.</div><div class="fg"><span class="fk">In general</span>So a long reference inside a skill costs almost nothing until it is used. A skill is worth creating when the same instruction or checklist keeps being pasted into chat, or when a section of the rules has grown into a procedure<a class="proof" href="https://code.claude.com/docs/en/skills" target="_blank" rel="noopener" data-quote="Anthropic: «Create a skill when you keep pasting the same instructions, checklist, or multi-step procedure into chat, or when a section of CLAUDE.md has grown into a procedure rather than a fact. Unlike CLAUDE.md content, a skill&#x27;s body loads only when it&#x27;s used» — code.claude.com/docs/en/skills" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Find a section of your rules that describes a procedure and move it into a skill with a precise description of when to use it.</div></div></section><section class="chapter" id="chat"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg></span>The same in a chat: projects and skills</h2><div class="io"><div><div class="k">Project instructions <span class="k-eq">≈ rules</span></div><div class="v">Role and format once, for every chat in the project<a class="proof" href="https://help.openai.com/en/articles/10169521-projects-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: a project keeps chats, files and instructions together; project instructions apply only inside it, and it can be shared with teammates. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/10169521" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://support.claude.com/en/articles/9517075-what-are-projects" target="_blank" rel="noopener" data-quote="Claude: “You can define project instructions for each project to further tailor Claude&#39;s responses. For example, instructing Claude to use a more formal tone or answer questions from the perspective of a specific role” — support.claude.com/en/articles/9517075" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div><div class="k">Project files <span class="k-eq">≈ bible</span></div><div class="v">Sample replies, policies and templates live in the project<a class="proof" href="https://support.claude.com/en/articles/9517075-what-are-projects" target="_blank" rel="noopener" data-quote="Claude: “You can upload relevant documents, text, code, or other files to a project&#39;s knowledge base, which Claude will use to better understand the context” — support.claude.com/en/articles/9517075" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div><div><div class="k">Skills <span class="k-eq">= skills</span></div><div class="v">A repeatable workflow with instructions and examples<a class="proof" href="https://support.claude.com/en/articles/12512180-use-skills-in-claude" target="_blank" rel="noopener" data-quote="Claude: “Skills extend Claude&#39;s capabilities by giving it access to specialized knowledge and workflows” — support.claude.com/en/articles/12512180" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://help.openai.com/en/articles/20001066-skills-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: skills are reusable workflows with instructions, examples and code, on Business, Enterprise and Edu plans. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/20001066" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Three places where a prompt outlives a single chat: instructions, files and skills.</div><div class="fg"><span class="fk">In general</span>A role, examples and format moved into a project work in every new chat without copying. A shared project gives the whole team one set of examples.</div><div class="fa"><span class="fk">Next step</span>Create a project for your most frequent weekly task and move the role and format from your best prompt into its instructions.</div></div></section><section class="chapter" id="pick"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v6M12 15v6M5 12H3M21 12h-2"/><circle cx="12" cy="12" r="3"/></svg></span>What goes where</h2><div class="tbl pk"><table><thead><tr><th>If it is…</th><th>Where</th></tr></thead><tbody><tr><td>a command, style or prohibition needed in every task</td><td><span class="ly-t" style="--c:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/><path d="M18 16l2 2-2 2"/></svg>Rules</span></td></tr><tr><td>a multi-step procedure needed now and then</td><td><span class="ly-t" style="--c:var(--c-work)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>Skill</span></td></tr><tr><td>requirements for one task</td><td><span class="ly-t" style="--c:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h4"/></svg>Spec</span></td></tr><tr><td>product knowledge and decisions made</td><td><span class="ly-t" style="--c:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 4h11a3 3 0 0 1 3 3v13H8a3 3 0 0 1-3-3z"/><path d="M5 17a3 3 0 0 1 3-3h11M12 7v4M10 9h4"/></svg>Bible</span></td></tr><tr><td>an agent error that keeps coming back</td><td><a href="/en/blog/harness-driven-development/#loop">rule or check · HDD</a></td></tr></tbody></table></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Five situations and five places.</div><div class="fg"><span class="fk">In general</span>Frequency and lifetime decide the place. What is always needed is kept short; what is rarely needed can be detailed.</div><div class="fa"><span class="fk">Next step</span>Review the rules once a week: move procedures into skills and decisions into the bible with a date.</div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/harness-driven-development/"><div class="k">Method</div><div class="t">Harness-Driven Development</div><div class="d">Agent error → environment rule</div></a><a href="/en/blog/harness-work-approaches/"><div class="k">Approaches</div><div class="t">Approaches to working with a harness</div><div class="d">Answer loop and review</div></a><a href="/en/blog/work-prompts-examples/"><div class="k">Practice</div><div class="t">Prompts for work tasks</div><div class="d">Five parts and six examples</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Comparison</div><div class="t">Comparing harnesses</div><div class="d">Claude Code, Codex, Cursor, Hermes</div></a></div></section><footer>Based on Anthropic, OpenAI, GitHub, Cursor and Cline docs; the source is behind the icon next to each claim. “Project bible” is a practitioner term; paraphrases are marked in the source tooltip.</footer></div>]]></content:encoded></item>
<item><title>Who to interview before buying AI tools: eight polar groups</title><link>https://www.urvanov.com/en/blog/who-to-interview-before-buying-ai-tools/</link><guid>https://www.urvanov.com/en/blog/who-to-interview-before-buying-ai-tools/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>How to pick 16 people from the report, a questionnaire and license lists, check team coverage and replacements, and decide what to ask them.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-gruppy-en"><p class="credit">Interview sampling design based on recommendations from <a href="https://t.me/Kseniya_Vasil" target="_blank" rel="noopener">@Kseniya_Vasil</a></p><div class="chain" aria-label="From report to interview list"><div class="st"><div class="viz"><div class="dots" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-code)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-code)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-work)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-work)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-chat)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-chat)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-silent)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-silent)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-none)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-none)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-light)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-light)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-proj)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-proj)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-team)"></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i class="on" style="background:var(--c-team)"></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div><div class="big">340<small>People in report</small></div></div><div class="arr" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="st"><div class="viz"><div class="six" aria-hidden="true"><i style="background:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 8l-4 4 4 4M16 8l4 4-4 4"/></svg></i><i style="background:var(--c-work)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 3L5 14h6l-1 7 8-11h-6z"/></svg></i><i style="background:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.5-4.5"/></svg></i><i style="background:var(--c-silent)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 15h2"/></svg></i><i style="background:var(--c-none)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="8"/><path d="M6.5 17.5l11-11"/></svg></i><i style="background:var(--c-light)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 4H5v16h5"/><path d="M14 8l4 4-4 4M18 12H9"/></svg></i><i style="background:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><path d="M3 7h7l2 2h9v10H3z"/></svg></i><i style="background:var(--c-team)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><rect x="14" y="14" width="6" height="6" rx="1"/></svg></i></div></div><div class="big">8<small>Polar groups</small></div></div><div class="arr" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="st"><div class="viz"><div class="thirteen" aria-hidden="true"><i style="background:var(--c-code)"></i><i style="background:var(--c-code)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-none)"></i><i style="background:var(--c-none)"></i><i style="background:var(--c-light)"></i><i style="background:var(--c-light)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-team)"></i><i style="background:var(--c-team)"></i></div></div><div class="big">16<small>Interviews</small></div></div></div><p class="cap">All numbers and names are examples</p><section class="chapter" id="why"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg></span>What decision it supports</h2><p>The <b>business task</b> comes from the <a href="/en/blog/chatgpt-enterprise-usage-report/#why">report</a>: for which work tasks the current set of AI tools falls short and what to test before buying. The report also says who makes the decision and by which signs. The sample decides whose tasks we will see in the interviews.</p><p>First, define which ways of getting tasks done you need to see: through the corporate AI tool, through other AI tools, by hand or through colleagues, and among people who tried the tool and quit. The <a href="/en/blog/chatgpt-enterprise-usage-report/">ChatGPT Enterprise usage report</a> is one of the sources: it finds the first group and those who quit. Users of other tools are found through a company-wide <a href="/en/blog/ai-interviews-without-leading-questions/#form">questionnaire</a> and license and purchase lists.</p><div class="io"><div><div class="k">Input</div><div class="v">Table of people from the report, a company-wide questionnaire, license and purchase lists</div></div><div><div class="k">What the method does</div><div class="v">Picks 2 people for each way of getting tasks done</div></div><div><div class="k">Output decision</div><div class="v">Who to talk to before buying and what to test, up to the conclusion that no new tool is needed</div></div></div></section><section class="chapter" id="top"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></svg></span>Why a top-by-activity list is not enough</h2><p class="why">Three ways to recruit 16 people. Dot color is the usage scenario. The most active people and volunteers are good respondents and belong in any sample, but they are not enough on their own.</p><div class="cmp"><div class="bad"><div class="h"><span class="s">partial</span>Top by messages</div><div class="row" aria-hidden="true"><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i></div><div class="m">scenarios: <b>2 of 8</b></div></div><div class="bad"><div class="h"><span class="s">partial</span>Volunteers</div><div class="row" aria-hidden="true"><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-code)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-code)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-code)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i></div><div class="m">scenarios: <b>3 of 8</b></div></div><div class="good"><div class="h"><span class="s">full</span>Polar groups</div><div class="row" aria-hidden="true"><i style="background:var(--c-code)"></i><i style="background:var(--c-code)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-none)"></i><i style="background:var(--c-none)"></i><i style="background:var(--c-light)"></i><i style="background:var(--c-light)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-team)"></i><i style="background:var(--c-team)"></i></div><div class="m">scenarios: <b>8 of 8</b></div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Top by messages covers 2 of 8 scenarios, volunteers cover 3, and polar groups cover all 8.</div><div class="fg"><span class="fk">In general</span>The most active and responsive people know the tool best and are worth inviting. They are similar to each other and together describe one or two scenarios. To hear the rest, the sample is filled with people at the extremes of other attributes.</div><div class="fa"><span class="fk">Next step</span>Take 2–3 people from the top by messages. Give the remaining slots to people with other scenarios: those who work only through Codex, quit the tool, use other tools, or run many projects.</div></div></section><section class="chapter" id="groups"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></span>Eight groups</h2><p class="why">Six groups come from report thresholds, "quit" from the last activity date, and "other tools" from the questionnaire. Each group has a question it helps test. The answer can be anything, including "no new tool is needed". The thresholds here are a guide: tune them so each group gets 2–5 people.</p><div class="groups"><div class="g"><span class="g-ico" style="background:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 8l-4 4 4 4M16 8l4 4-4 4"/></svg></span><div><div class="g-t">Most active in code</div><span class="g-c">code &gt; $200 / 3 mo</span><div class="g-q">what is missing in development: a tool, repository access, or nothing</div><div class="g-p">Hana Sato, Luis Moreno</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-work)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 3L5 14h6l-1 7 8-11h-6z"/></svg></span><div><div class="g-t">Agent tasks</div><span class="g-c">agent &gt; $60 / 3 mo</span><div class="g-q">where the agent falls short and why: data, the task, or the agent itself</div><div class="g-p">Mira Castellano, Tomás Reid</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.5-4.5"/></svg></span><div><div class="g-t">Intensive research</div><span class="g-c">&gt; 3,000 msgs, chat is primary</span><div class="g-q">how they check answers and whether the current search is enough</div><div class="g-p">Jonas Keller, Aiko Lind</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-silent)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 15h2"/></svg></span><div><div class="g-t">Codex only</div><span class="g-c">0 msgs and &gt; $20 / 3 mo</span><div class="g-q">which tasks they handle without chat and whether they need anything else</div><div class="g-p">Ben Ortiz, Lena Moss</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-none)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="8"/><path d="M6.5 17.5l11-11"/></svg></span><div><div class="g-t">Inactive</div><span class="g-c">0 msgs and $0 for the period</span><div class="g-q">how they get their tasks done and which options they considered</div><div class="g-p">Pavel Novak, Sara Quinn</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-light)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 4H5v16h5"/><path d="M14 8l4 4-4 4M18 12H9"/></svg></span><div><div class="g-t">Tried and quit</div><span class="g-c">had messages, 0 in the last 60 days</span><div class="g-q">why they stopped: result, time, security, or the task went away</div><div class="g-p">Farah Nasser, Yara Selim</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><path d="M3 7h7l2 2h9v10H3z"/></svg></span><div><div class="g-t">Project organizers</div><span class="g-c">≥ 6 active projects</span><div class="g-q">what projects give them and what they lack</div><div class="g-p">Elif Demir, Rafael Costa</div></div></div><div class="g"><span class="g-ico" style="background:var(--c-team)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="6" height="6" rx="1"/><rect x="14" y="4" width="6" height="6" rx="1"/><rect x="4" y="14" width="6" height="6" rx="1"/><rect x="14" y="14" width="6" height="6" rx="1"/></svg></span><div><div class="g-t">Other tools</div><span class="g-c">per questionnaire: main AI tool is not the corporate one</span><div class="g-q">what is better in the other tool and whether the current one can offer it</div><div class="g-p">Nadia Rahimi, Oskar Berg</div></div></div></div><div class="stack" aria-label="16 interviews by group"><div class="seg" style="flex:2;background:var(--c-code)">2</div><div class="seg" style="flex:2;background:var(--c-work)">2</div><div class="seg" style="flex:2;background:var(--c-chat)">2</div><div class="seg" style="flex:2;background:var(--c-silent)">2</div><div class="seg" style="flex:2;background:var(--c-none);color:var(--ink)">2</div><div class="seg" style="flex:2;background:var(--c-light);color:var(--ink)">2</div><div class="seg" style="flex:2;background:var(--c-proj)">2</div><div class="seg" style="flex:2;background:var(--c-team)">2</div></div><div class="legend"><span><i style="background:var(--c-code)"></i>code</span><span><i style="background:var(--c-work)"></i>agent</span><span><i style="background:var(--c-chat)"></i>research</span><span><i style="background:var(--c-silent)"></i>Codex only</span><span><i style="background:var(--c-none)"></i>inactive</span><span><i style="background:var(--c-light)"></i>quit</span><span><i style="background:var(--c-proj)"></i>projects</span><span><i style="background:var(--c-team)"></i>other tools</span></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>16 conversations: two in each of the eight groups.</div><div class="fg"><span class="fk">In general</span>Two or three people per group show whether a problem repeats: if two out of three say the same thing, that is a signal. People with average values are left out: their answers resemble neighboring groups and add no new scenarios across 16 conversations.</div><div class="fa"><span class="fk">Next step</span>In each group, sort candidates by its threshold and take the two with the most extreme values, from different teams where possible. If a person falls into two groups, keep them in the one where their value is more extreme and take the next candidate in the other.</div></div></section><section class="chapter" id="teams"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16.5v.5"/></svg></span>Team coverage and replacements</h2><p class="why">A separate step after recruiting that does not change the groups: how many selected people fall in each team and who replaces those who decline.</p><div class="tbl"><table><thead><tr><th>Team</th><th>Regular users</th><th>Selected</th><th>Status</th></tr></thead><tbody><tr><td>Team A</td><td><div class="dbar"><span style="width:74%"></span></div></td><td><div class="cov"><i style="background:var(--c-code)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-proj)"></i><i style="background:var(--c-light)"></i></div></td><td><span class="tag ok">covered</span></td></tr><tr><td>Team B</td><td><div class="dbar"><span style="width:66%"></span></div></td><td><div class="cov"><i style="background:var(--c-work)"></i><i style="background:var(--c-work)"></i><i style="background:var(--c-chat)"></i><i style="background:var(--c-none)"></i></div></td><td><span class="tag ok">covered</span></td></tr><tr><td>Team C</td><td><div class="dbar"><span style="width:51%"></span></div></td><td><div class="cov"><i style="background:var(--c-code)"></i><i style="background:var(--c-silent)"></i><i style="background:var(--c-none)"></i><i style="background:var(--c-proj)"></i></div></td><td><span class="tag ok">covered</span></td></tr><tr><td>Team D</td><td><div class="dbar"><span style="width:34%"></span></div></td><td><div class="cov"><i style="background:var(--c-team)"></i></div></td><td><span class="tag ok">after replacement</span></td></tr><tr><td>Team E</td><td><div class="dbar"><span style="width:18%"></span></div></td><td><div class="cov"><i style="background:var(--c-light)"></i><i style="background:var(--c-team)"></i></div></td><td><span class="tag ok">after replacement</span></td></tr></tbody></table></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>After recruiting by group, Teams D and E had nobody. Three candidates were replaced with people from D and E with the same behavior, and all five teams are now covered.</div><div class="fg"><span class="fk">In general</span>Spend and message thresholds catch extreme users. A team where everyone uses the tool a little never crosses a threshold, and its tasks drop out of the research. That is why teams are checked as a separate step.</div><div class="fa"><span class="fk">Next step</span>Lay the selected people out by team. If a team has nobody, replace one candidate in a fitting group with a person from that team with the same behavior. Replace anyone who declines with the next candidate of the same group by its threshold.</div></div></section><section class="chapter" id="ask"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg></span>What to learn in the interview</h2><p class="why">The conversation starts from the last work task, not from the tool: what they needed to get, what means they had, what they chose, and how they got to the result. The full script is in the <a href="/en/blog/ai-interviews-without-leading-questions/#script">interview article</a>.</p><div class="tl"><div class="ph"><div class="ph-h" style="background:var(--c-chat)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/></svg>Task</div><ul><li><b>The last work task</b><span>What they needed to get and for whom</span></li><li><b>Means and choice</b><span>What they had, what they chose and why</span></li></ul></div><div class="ph"><div class="ph-h" style="background:var(--c-proj)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>Path</div><ul><li><b>How they got to the result</b><span>What they used as is, what they finished themselves</span></li><li><b>Effort and constraints</b><span>Time, data, access, security</span></li></ul></div><div class="ph"><div class="ph-h" style="background:var(--c-work)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>A successful case</div><ul><li><b>When it went well</b><span>What was different then</span></li></ul></div><div class="ph"><div class="ph-h" style="background:var(--c-code)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19h16M7 15l4-4 3 3 5-6"/></svg>Quitting and switching</div><ul><li><b>Quit or changed tools</b><span>What they switched to and why</span></li></ul></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Six points: four about one task, a successful case, and quitting or switching.</div><div class="fg"><span class="fk">In general</span>A story about a past task gives facts: you see where the person chose AI, where another way, and why. The successful case shows what already works; quitting and switching show why tools get replaced. A forecast about the future cannot be checked.</div><div class="fa"><span class="fk">Next step</span>Ask them to name their last work task in the first minutes and run the whole conversation on it. If the person does not mention AI, ask which options they considered, not why they do not use it.</div></div></section><section class="chapter" id="order"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M9 6h11M9 12h11M9 18h11M4 6h.01M4 12h.01M4 18h.01"/></svg></span>Workflow</h2><ol class="steps"><li><span class="step-n">1</span><div><div class="step-t">Collect candidates into eight groups</div><div class="step-d">Six groups from report thresholds, "quit" from the last activity date, "other tools" from the questionnaire</div></div></li><li><span class="step-n">2</span><div><div class="step-t">Keep 2 people per group</div><div class="step-d">From different teams if you have a choice; one person in one group only</div></div></li><li><span class="step-n">3</span><div><div class="step-t">Check team coverage</div><div class="step-d">If a team has nobody, replace one candidate with a person from it with the same behavior</div></div></li><li><span class="step-n">4</span><div><div class="step-t">Schedule 30-minute interviews</div><div class="step-d">The conversation starts from the last work task: what they needed to get, what means they had, what they chose, and how they got to the result. With those who quit, also discuss why they stopped</div></div></li></ol><div class="limit"><span class="i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 7v6M12 17v.5"/></svg></span><div><b>Limitation.</b> 16 interviews show which problems occur and what they look like in real work. They cannot tell you how many people in the company face each one. To learn the scale, send the whole company a short <a href="/en/blog/ai-interviews-without-leading-questions/#form">questionnaire</a>, written after the interviews. If the problems are not confirmed, that is also a result: no new tool is needed.</div></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links"><a href="/en/blog/chatgpt-enterprise-usage-report/"><div class="k">Report</div><div class="t">ChatGPT Enterprise usage report</div><div class="d">How to build the usage report that the people table comes from</div></a><a href="/en/blog/ai-interviews-without-leading-questions/"><div class="k">Interviews</div><div class="t">Interviews without leading questions</div><div class="d">How to run the conversation by voice or questionnaire and collect answers in Airtable</div></a></div></section><footer>Interview sampling design based on recommendations from <a href="https://t.me/Kseniya_Vasil" target="_blank" rel="noopener">@Kseniya_Vasil</a>. All names, teams, and numbers in the examples are fictional.</footer></div>]]></content:encoded></item>
<item><title>Prompts for work tasks: five parts and six examples for ChatGPT and Claude</title><link>https://www.urvanov.com/en/blog/work-prompts-examples/</link><guid>https://www.urvanov.com/en/blog/work-prompts-examples/</guid><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><description>Prompts for work with an AI chat: the parts of a good work prompt, what a weak and a strong ask look like, six ready templates for common tasks and how to keep them in a project, based on the Anthropic, OpenAI and Google guides.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div class="s-rich s-rich-prompts-en"><div class="flow lead" aria-label="One ask, two results"><div class="lane"><div class="lane-h" style="color:var(--warn)"><span class="dot" style="background:var(--warn)"></span>One sentence</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg><b>Ask</b><small>“write a reply to the customer”</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="14" height="14" rx="3"/><path d="M12 8.5l1.2 2.3 2.3 1.2-2.3 1.2-1.2 2.3-1.2-2.3-2.3-1.2 2.3-1.2z"/></svg><b>Model</b><small>guesses the context</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9.5 12.5l5 5M14.5 12.5l-5 5"/></svg><b>Generic answer</b><small>rewrite by hand</small></span></div></div><div class="lane"><div class="lane-h" style="color:var(--accent)"><span class="dot" style="background:var(--accent)"></span>Six parts</div><div class="chainrow"><span class="nd"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="3.0" width="16" height="2.2" rx="1" style="fill:var(--c-chat)"/><rect x="4" y="6.2" width="16" height="2.2" rx="1" style="fill:var(--c-proj)"/><rect x="4" y="9.4" width="16" height="2.2" rx="1" style="fill:var(--c-work)"/><rect x="4" y="12.600000000000001" width="16" height="2.2" rx="1" style="fill:var(--c-code)"/><rect x="4" y="15.8" width="16" height="2.2" rx="1" style="fill:var(--c-silent)"/><rect x="4" y="19.0" width="16" height="2.2" rx="1" style="fill:var(--c-team)"/></svg><b>Prompt</b><small>role, data, example, format</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="14" height="14" rx="3"/><path d="M12 8.5l1.2 2.3 2.3 1.2-2.3 1.2-1.2 2.3-1.2-2.3-2.3-1.2 2.3-1.2z"/></svg><b>Model</b><small>sees everything it needs</small></span><span class="ar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span><span class="nd"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 14l2 2 4-4"/></svg><b>Draft</b><small>minor edits</small></span></div></div></div><p class="cap">The model is the same in both cases. The result depends on what the prompt says: six parts that recur in the Anthropic, OpenAI and Google guides.</p><section class="chapter" id="model"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="5" cy="12" r="2.5"/><circle cx="19" cy="5" r="2.5"/><circle cx="19" cy="19" r="2.5"/><path d="M7.3 11l9.4-4.6M7.3 13l9.4 4.6"/></svg></span>Human-in-the-loop: the path of one request</h2><div class="dm-wrap"><svg class="dm" viewBox="0 0 980 410" role="img" aria-label="Diagram: a task is described by a six-part prompt, data from sources goes into it whole, the model answers, the reader makes a decision, a check loops back to refine the prompt, a good prompt is saved as a template in a project and reused for the next task"><title>Diagram: a task is described by a six-part prompt, data from sources goes into it whole, the model answers, the reader makes a decision, a check loops back to refine the prompt, a good prompt is saved as a template in a project and reused for the next task</title><defs><marker id="dm-ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" class="dm-arh"/></marker></defs><rect class="dm-box" x="200" y="16" width="300" height="286" rx="8"/><text class="dm-bt" x="220" y="44">Prompt</text><rect class="dm-p" x="218" y="58" width="264" height="30" rx="4"/><rect x="218" y="58" width="6" height="30" rx="2" style="fill:var(--c-chat)"/><text class="dm-pt" x="236" y="78">Role</text><rect class="dm-p" x="218" y="96" width="264" height="30" rx="4"/><rect x="218" y="96" width="6" height="30" rx="2" style="fill:var(--c-proj)"/><text class="dm-pt" x="236" y="116">Audience and goal</text><rect class="dm-p" x="218" y="134" width="264" height="30" rx="4"/><rect x="218" y="134" width="6" height="30" rx="2" style="fill:var(--c-work)"/><text class="dm-pt" x="236" y="154">The whole data</text><rect class="dm-p" x="218" y="172" width="264" height="30" rx="4"/><rect x="218" y="172" width="6" height="30" rx="2" style="fill:var(--c-code)"/><text class="dm-pt" x="236" y="192">Example · 1–3</text><rect class="dm-p" x="218" y="210" width="264" height="30" rx="4"/><rect x="218" y="210" width="6" height="30" rx="2" style="fill:var(--c-silent)"/><text class="dm-pt" x="236" y="230">Format</text><rect class="dm-p" x="218" y="248" width="264" height="30" rx="4"/><rect x="218" y="248" width="6" height="30" rx="2" style="fill:var(--c-team)"/><text class="dm-pt" x="236" y="268">Question last</text><rect class="dm-n key" x="20" y="70" width="140" height="52" rx="6"/><text class="dm-t" x="90.0" y="101.0" text-anchor="middle">Task</text><rect class="dm-n" x="12" y="336" width="176" height="52" rx="6"/><text class="dm-t" x="100.0" y="367.0" text-anchor="middle">Template in a project</text><rect class="dm-n key" x="560" y="70" width="120" height="52" rx="6"/><text class="dm-t" x="620.0" y="101.0" text-anchor="middle">Model</text><rect class="dm-n" x="720" y="70" width="110" height="52" rx="6"/><text class="dm-t" x="775.0" y="101.0" text-anchor="middle">Answer</text><rect class="dm-n" x="860" y="70" width="110" height="52" rx="6"/><text class="dm-t" x="915.0" y="101.0" text-anchor="middle">Reader</text><rect class="dm-n" x="860" y="172" width="110" height="46" rx="6"/><text class="dm-t" x="915.0" y="200.0" text-anchor="middle">Decision</text><rect class="dm-n" x="720" y="172" width="110" height="46" rx="6"/><text class="dm-t" x="775.0" y="200.0" text-anchor="middle">Check</text><rect class="dm-n" x="220" y="336" width="260" height="52" rx="6"/><text class="dm-t" x="350.0" y="360.0" text-anchor="middle">Sources</text><text class="dm-s" x="350.0" y="377.0" text-anchor="middle">thread · document · table</text><path class="dm-e" d="M160,96 L198,96" marker-end="url(#dm-ar)"/><text class="dm-el" x="194" y="62" text-anchor="end">describes</text><path class="dm-e" d="M500,96 L558,96" marker-end="url(#dm-ar)"/><text class="dm-el" x="508" y="62" text-anchor="start">send</text><path class="dm-e" d="M680,96 L718,96" marker-end="url(#dm-ar)"/><text class="dm-el" x="699" y="62" text-anchor="middle">answers</text><path class="dm-e" d="M830,96 L858,96" marker-end="url(#dm-ar)"/><path class="dm-e" d="M915,122 L915,170" marker-end="url(#dm-ar)"/><text class="dm-el" x="922" y="150" text-anchor="start">makes</text><path class="dm-e" d="M775,122 L775,170" marker-end="url(#dm-ar)"/><text class="dm-el" x="782" y="150" text-anchor="start">check</text><path class="dm-e dash" d="M720,206 C 640,206 600,250 502,250" marker-end="url(#dm-ar)"/><text class="dm-el" x="610" y="268" text-anchor="middle">missed — refine</text><path class="dm-e" d="M350,336 L350,304" marker-end="url(#dm-ar)"/><text class="dm-el" x="358" y="324" text-anchor="start">whole</text><path class="dm-e" d="M200,280 C 140,300 110,310 100,334" marker-end="url(#dm-ar)"/><text class="dm-el" x="150" y="314" text-anchor="end">save</text><path class="dm-e dash" d="M36,336 C 10,260 10,180 40,124" marker-end="url(#dm-ar)"/><text class="dm-el" x="34" y="236" text-anchor="start">next task</text><text class="dm-el" x="845" y="62" text-anchor="middle">reads</text></svg></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A person holds every key point: sets the task, builds the prompt, checks the answer, sends it back to refine and makes the decision. The model only answers what made it into the request.</div><div class="fg"><span class="fk">In general</span>Every arrow has its own checkpoint: data goes in whole, the answer is checked against who needs it, and a good request is saved as a template so the next task of the same kind starts from it.</div><div class="fa"><span class="fk">Next step</span>Before writing the request, name the reader and the decision they will make from the answer: the role and the format follow from that.</div></div><a class="hdd-cta" href="/en/blog/harness-driven-development/"><span class="hdd-k">Next step · HDD</span><b>Harness-Driven Development</b><span>How to turn the check in this diagram into a rule that works for every next task</span></a></section><section class="chapter" id="parts"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></span>Five parts of a prompt</h2><div class="pa" role="img" aria-label="Prompt anatomy: role, audience and goal, the whole data in tags, example, format, question last"><div class="pa-win"><div class="pa-bar"><i></i><i></i><i></i></div><div class="pa-b pa-role" title="Role: “You are a support agent.” One sentence sets the tone and level" aria-label="Role: “You are a support agent.” One sentence sets the tone and level"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg></span><b>Role</b><div class="pa-v"><span class="pa-l"><i style="width:55%"></i></span></div><span class="pa-p"><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Setting a role in the system prompt focuses Claude&#39;s behavior and tone for your use case. Even a single sentence makes a difference” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="pa-b pa-who" title="Who and why: Who reads the result and what decision it feeds" aria-label="Who and why: Who reads the result and what decision it feeds"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></svg></span><b>Audience and goal</b><div class="pa-v"><span class="pa-flow"><span class="pa-doc"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg></span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg><span class="pa-ppl"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 20c0-3 3-5 6-5s6 2 6 5M15 20c0-2 1.5-3.5 3.5-3.5S22 18 22 20"/></svg></span></span></div><span class="pa-p"><a class="proof" href="https://academy.openai.com/public/clubs/work-users-ynjqu/resources/prompting" target="_blank" rel="noopener" data-quote="OpenAI Academy: “Be clear about what you need ChatGPT to do. Outline what you want, who it&#39;s for, and why it matters” — academy.openai.com, Prompting" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Providing context or motivation behind your instructions, such as explaining to Claude why such behavior is important, can help Claude better understand your goals and deliver more targeted responses” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="pa-b pa-data" title="Full data: Paste the thread, document or table in full. Long input on top, the question at the end" aria-label="Full data: Paste the thread, document or table in full. Long input on top, the question at the end"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg></span><b>The whole data</b><div class="pa-v"><span class="pa-tag">&lt;data&gt;</span><span class="pa-l tall"><i style="width:92%"></i><i style="width:78%"></i><i style="width:88%"></i><i style="width:64%"></i><i style="width:84%"></i><i style="width:70%"></i><i style="width:90%"></i><i style="width:58%"></i><i style="width:80%"></i></span><span class="pa-tag">&lt;/data&gt;</span></div><span class="pa-p"><a class="proof" href="https://academy.openai.com/public/clubs/work-users-ynjqu/resources/prompting" target="_blank" rel="noopener" data-quote="OpenAI Academy: “Add any background (or documentation) that will help” — academy.openai.com, Prompting" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Place your long documents and inputs near the top of your prompt, above your query, instructions, and examples”; “Queries at the end can improve response quality by up to 30 percent in tests” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="pa-b pa-ex" title="Example: One to three samples of the tone or format you want" aria-label="Example: One to three samples of the tone or format you want"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M7 10h6M7 14h10"/></svg></span><b>Example</b><div class="pa-v"><span class="pa-tag">&lt;example&gt;</span><span class="pa-cards"><i></i><i></i><i class="opt"></i></span><span class="pa-tag">&lt;/example&gt;</span><small>1–3</small></div><span class="pa-p"><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Include 3–5 examples for best results” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://www.kaggle.com/whitepaper-prompt-engineering" target="_blank" rel="noopener" data-quote="Google, Prompt Engineering: its best practices include providing examples, being specific about the output and using instructions over constraints. Paraphrased — kaggle.com/whitepaper-prompt-engineering" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="pa-b pa-fmt" title="Format: “5 bullets, one line each.” Say what to do, instead of listing bans" aria-label="Format: “5 bullets, one line each.” Say what to do, instead of listing bans"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11"/><circle cx="4.5" cy="6" r="1"/><circle cx="4.5" cy="12" r="1"/><circle cx="4.5" cy="18" r="1"/></svg></span><b>Format</b><div class="pa-v"><span class="pa-list"><i></i><i></i><i></i><i></i><i></i></span><small>5 points</small></div><span class="pa-p"><a class="proof" href="https://academy.openai.com/public/clubs/work-users-ynjqu/resources/prompting" target="_blank" rel="noopener" data-quote="OpenAI Academy: “Tell ChatGPT how you&#39;d like the response” — academy.openai.com, Prompting" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Tell Claude what to do instead of what not to do” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div><div class="pa-b pa-q" title="Paste the thread, document or table in full. Long input on top, the question at the end" aria-label="Paste the thread, document or table in full. Long input on top, the question at the end"><span class="pa-i"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.7.3-1 .9-1 1.7M12 17h.01"/></svg></span><b>Question last</b><div class="pa-v"><span class="pa-l"><i style="width:40%"></i></span><span class="pa-qm">?</span></div><span class="pa-p"></span></div></div><div class="pa-rail"><span class="pa-down"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4v16M6 14l6 6 6-6"/></svg></span><small>order</small><div class="pa-side" title="Tags for parts: &lt;thread&gt;…&lt;/thread&gt; keeps data apart from the instruction" aria-label="Tags for parts: &lt;thread&gt;…&lt;/thread&gt; keeps data apart from the instruction"><span class="pa-tag big">&lt;…&gt;</span><small>tags</small><span class="pa-p"><a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Wrapping each type of content in its own tag (for example, &lt;instructions&gt;, &lt;context&gt;, &lt;input&gt;) reduces misinterpretation” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a></span></div></div></div><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Five parts plus tags, each backed by an official guide.</div><div class="fg"><span class="fk">In general</span>The model knows only what the prompt says. Anthropic suggests a test: show the prompt to a colleague with no context; if they are confused, the model will be too<a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Show your prompt to a colleague with minimal context on the task and ask them to follow it. If they&#39;d be confused, Claude will be too” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Open your last prompt and mark which of the five parts are missing. Add a role and a format: two sentences.</div></div></section><section class="chapter" id="examples"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="15" rx="2"/><path d="M3 9h18M8 5v4"/></svg></span>Six examples</h2><div class="tabs"><input type="radio" name="ex-en" id="ex-en-client" checked><input type="radio" name="ex-en" id="ex-en-meeting"><input type="radio" name="ex-en" id="ex-en-summary"><input type="radio" name="ex-en" id="ex-en-table"><input type="radio" name="ex-en" id="ex-en-style"><input type="radio" name="ex-en" id="ex-en-research"><nav class="tb"><label for="ex-en-client"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg></span>Customer reply</label><label for="ex-en-meeting"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M8 3v4M16 3v4M3 10h18"/></svg></span>Meeting prep</label><label for="ex-en-summary"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16M4 10h16M4 15h10M4 20h6"/></svg></span>Thread summary</label><label for="ex-en-table"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg></span>Table analysis</label><label for="ex-en-style"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20l4-1 11-11-3-3L5 16z"/><path d="M14 6l3 3"/></svg></span>Company voice</label><label for="ex-en-research"><span class="tb-i" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.3-4.3"/></svg></span>Research</label></nav><div class="tp" id="client"><h3 class="tp-h">Reply to a customer thread</h3><p class="why">The customer writes for the third time; the tone must stay calm, and only what the thread already says can be promised.</p><div class="parts"><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">You are a support agent at [company].&#10;Below is the full thread with the customer.&#10;&lt;thread&gt;&#10;[paste in full]&#10;&lt;/thread&gt;&#10;Write the next reply. Tone: calm and friendly, like this example:&#10;&lt;example&gt;&#10;[one good past reply]&#10;&lt;/example&gt;&#10;No more than 5 sentences. Mention dates only if they appear in the thread.</pre><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A role, the thread in tags, a tone sample and two format rules.</div><div class="fg"><span class="fk">In general</span>A past reply sets the tone better than any adjective. The dates rule is phrased as a permission with a condition, and the model follows it literally.</div><div class="fa"><span class="fk">Next step</span>Keep two or three of the team’s best replies and drop one into the example block.</div></div></div><div class="tp" id="meeting"><h3 class="tp-h">Preparing for a meeting</h3><p class="why">A 30-minute meeting tomorrow; the materials are scattered across threads and docs.</p><div class="parts"><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">Tomorrow I meet [whom] about [topic], 30 minutes. My goal is [the decision I need].&#10;&lt;materials&gt;&#10;[threads and documents]&#10;&lt;/materials&gt;&#10;Prepare:&#10;1. Three questions to settle at the meeting.&#10;2. For each, what the materials already say, with a short quote.&#10;3. What I need to find out before the meeting.&#10;Format: a three-column table.</pre><p class="cap">OpenAI Academy has an agenda template with time estimates<a class="proof" href="https://academy.openai.com/public/resources/chatgpt-for-any-role" target="_blank" rel="noopener" data-quote="OpenAI Academy, ChatGPT for any role: “Create a structured agenda for a meeting about [topic]. Break the agenda into sections with time estimates and goals for each section” — academy.openai.com" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The meeting goal, materials in tags and a numbered list of what to return.</div><div class="fg"><span class="fk">In general</span>The meeting goal filters the materials. Numbered steps help when order and completeness matter<a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Show your prompt to a colleague with minimal context on the task and ask them to follow it. If they&#39;d be confused, Claude will be too” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</div><div class="fa"><span class="fk">Next step</span>Before any meeting of 30 minutes or more, run the materials through this prompt and open with its table.</div></div></div><div class="tp" id="summary"><h3 class="tp-h">Summary of a long thread</h3><p class="why">A chat of 200 messages; you need to know what was decided and who does what.</p><div class="parts"><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">&lt;thread&gt;&#10;[paste in full]&#10;&lt;/thread&gt;&#10;First, copy the exact quotes where decisions are made or tasks are assigned.&#10;Then build a summary from those quotes:&#10;— decisions;&#10;— tasks with owners and dates;&#10;— open questions.&#10;One line per item. If a quote names no owner, write “unassigned”.</pre><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The long thread sits on top, the task at the end, quotes first, then the summary.</div><div class="fg"><span class="fk">In general</span>For long documents Anthropic advises asking for quotes first<a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “For long document tasks, ask Claude to quote relevant parts of the documents first before carrying out its task” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a> and placing the question after the data: in tests that improved quality by up to 30%<a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Place your long documents and inputs near the top of your prompt, above your query, instructions, and examples”; “Queries at the end can improve response quality by up to 30 percent in tests” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. The “unassigned” rule stops the model from inventing an owner.</div><div class="fa"><span class="fk">Next step</span>For any thread longer than one screen, start by asking for quotes.</div></div></div><div class="tp" id="table"><h3 class="tp-h">Analysing a table</h3><p class="why">A month of tickets exported to CSV; find what changed.</p><div class="parts"><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">Attached is an export of [tickets] for [period], CSV.&#10;Count [tickets] by [topic] and show the 5 biggest changes versus last month.&#10;For each, the number and one line on what may explain it.&#10;Show the code you used so I can check it.</pre><p class="cap">Both ChatGPT and Claude process the file in an isolated sandbox<a class="proof" href="https://help.openai.com/en/articles/8437071-data-analysis-with-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: for data analysis it writes and runs Python in an isolated environment; review the code, output and assumptions before relying on the result. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/8437071" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://support.claude.com/en/articles/12111783-create-and-edit-files-with-claude" target="_blank" rel="noopener" data-quote="Claude: “When Claude executes code or creates files, it operates within an isolated, sandboxed container” — support.claude.com/en/articles/12111783" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>The whole file, an exact metric and breakdown, a “top 5” limit and a request for the code.</div><div class="fg"><span class="fk">In general</span>The model computes with code in a sandbox, and code can be re-read. OpenAI advises checking the code, output and assumptions before relying on the result.</div><div class="fa"><span class="fk">Next step</span>Check one number from the answer by hand. If it matches, trust the rest more.</div></div></div><div class="tp" id="style"><h3 class="tp-h">Text in the company’s voice</h3><p class="why">You need a post or email that sounds like the team, not like a template.</p><div class="parts"><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">Here are three of our posts that landed well:&#10;&lt;example&gt;[post 1]&lt;/example&gt;&#10;&lt;example&gt;[post 2]&lt;/example&gt;&#10;&lt;example&gt;[post 3]&lt;/example&gt;&#10;Write a post about [topic] in the same style: length, tone and structure as in the examples.&#10;For whom: [audience]. Why: [what we want the reader to do].</pre><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>Three examples in tags and one line on who it is for and why.</div><div class="fg"><span class="fk">In general</span>Anthropic recommends 3–5 examples<a class="proof" href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener" data-quote="Anthropic: “Include 3–5 examples for best results” — platform.claude.com, Prompting best practices" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>; Google’s guide also lists examples as the first practice<a class="proof" href="https://www.kaggle.com/whitepaper-prompt-engineering" target="_blank" rel="noopener" data-quote="Google, Prompt Engineering: its best practices include providing examples, being specific about the output and using instructions over constraints. Paraphrased — kaggle.com/whitepaper-prompt-engineering" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>. A style shown in examples is copied more precisely than a style described in words.</div><div class="fa"><span class="fk">Next step</span>Put good texts into a project and use them as examples, so you do not paste them every time.</div></div></div><div class="tp" id="research"><h3 class="tp-h">Researching a topic</h3><p class="why">You need an overview of a market or practice with sources, half a day of searching by hand.</p><div class="parts"><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="3.5"/><path d="M5 20a7 7 0 0 1 14 0"/></svg>Role</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01"/></svg>Who and why</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4M9 12h6M9 16h6"/></svg>Full data</span><span class="pt off"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 13h5"/><path d="M15 15l2 2 3-3"/></svg>Example</span><span class="pt"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h13"/></svg>Format</span></div><pre class="prompt">Research: [question].&#10;For whom: [audience]. Why: [the decision to make].&#10;Data no older than [year].&#10;Output: a table [columns] and a 5-point conclusion.&#10;A source link for every fact. If there is no data, say so.</pre><p class="cap">Both chats have a deep research mode: deep research in ChatGPT and Research in Claude<a class="proof" href="https://help.openai.com/en/articles/10500283-deep-research-in-chatgpt" target="_blank" rel="noopener" data-quote="ChatGPT: deep research gathers and synthesises information from the web into a report, takes 5 to 30 minutes and includes source links. Paraphrased from the OpenAI Help Center — help.openai.com/en/articles/10500283" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a><a class="proof" href="https://support.claude.com/en/articles/11088861-use-research-on-claude" target="_blank" rel="noopener" data-quote="Claude: Research is “conducting multiple searches that build on each other”, answers come “complete with easy-to-check citations”; “available for users with paid Claude plans (Pro, Max, Team, or Enterprise)” — support.claude.com/en/articles/11088861" aria-label="Source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/></svg></a>.</p><div class="finding"><b>Takeaway</b><div class="fc"><span class="fk">In this example</span>A goal, a freshness limit and an output format with links.</div><div class="fg"><span class="fk">In general</span>In research mode the model runs a series of searches and returns a report with links. Links let you check every fact, and “if there is no data” stops gaps being filled with guesses.</div><div class="fa"><span class="fk">Next step</span>Open two or three links from the report and check the fact against the source before passing the conclusion on.</div></div></div></div></section><section class="chapter" id="learn"><h2><span class="ico" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 21V4h11l-2 4 2 4H5"/></svg></span>What to study next</h2><p class="why">Start with the 7-minute tutorial: it explains why the techniques in this article work. Then the prompting guides, and the courses when you have time.</p><div class="sublabel" style="margin-top:22px">Foundations: how AI works</div><div class="links two"><a href="https://academy.claude.com/tutorials/the-4-properties-of-ai" target="_blank" rel="noopener"><div class="k">Claude Academy · tutorial, 7 minutes</div><div class="t">The 4 properties of AI</div><div class="d">Next-token prediction, knowledge, working memory, steerability: where the model’s strengths and weaknesses come from</div></a><a href="https://academy.claude.com/courses/ai-capabilities-and-limitations" target="_blank" rel="noopener"><div class="k">Claude Academy · course, 13 lessons, 3.5 hours</div><div class="t">AI Capabilities and Limitations</div><div class="d">Why a model confidently makes things up, where context runs out and which instructions are reliable</div></a><a href="https://academy.claude.com/courses/ai-fluency-framework-foundations" target="_blank" rel="noopener"><div class="k">Claude Academy · course, 14 lessons, 4 hours</div><div class="t">AI Fluency: Framework & Foundations</div><div class="d">Four skills: what to delegate, how to describe the task, how to check the result and who owns it</div></a></div><div class="sublabel" style="margin-top:22px">Prompting</div><div class="links two"><a href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" target="_blank" rel="noopener"><div class="k">Anthropic · docs</div><div class="t">Prompting best practices</div><div class="d">The main reference: clarity, examples, role, XML tags, long documents</div></a><a href="https://claude.com/blog/best-practices-for-prompt-engineering" target="_blank" rel="noopener"><div class="k">Anthropic · blog</div><div class="t">Best practices for prompt engineering</div><div class="d">General prompting craft beyond a specific model</div></a><a href="https://github.com/anthropics/prompt-eng-interactive-tutorial" target="_blank" rel="noopener"><div class="k">Anthropic · tutorial</div><div class="t">Interactive tutorial</div><div class="d">9 chapters with exercises, from prompt structure to XML tags and examples</div></a><a href="https://www.kaggle.com/whitepaper-prompt-engineering" target="_blank" rel="noopener"><div class="k">Google · whitepaper</div><div class="t">Prompt Engineering</div><div class="d">Techniques and best practices: examples, output format, instructions over constraints</div></a><a href="https://academy.openai.com/public/clubs/work-users-ynjqu/resources/prompting" target="_blank" rel="noopener"><div class="k">OpenAI Academy</div><div class="t">Prompting</div><div class="d">What, for whom and why, context, output format, iteration</div></a><a href="https://academy.openai.com/public/resources/chatgpt-for-any-role" target="_blank" rel="noopener"><div class="k">OpenAI Academy</div><div class="t">ChatGPT for any role</div><div class="d">Ready work-prompt templates by task and role</div></a></div><div class="sublabel" style="margin-top:22px">For teams and admins</div><div class="links two"><a href="https://support.claude.com/en/articles/14782391-claude-enterprise-consumption-guide" target="_blank" rel="noopener"><div class="k">Claude · help center</div><div class="t">Claude Enterprise consumption guide</div><div class="d">How tokens are spent: Claude Code and Cowork use far more than plain chat; group limits and a default model</div></a></div></section><section class="chapter" id="next"><h2>Further reading</h2><div class="links two"><a href="/en/blog/harness-work-approaches/"><div class="k">Approaches</div><div class="t">If the answer misses</div><div class="d">Answer loop and review that fixes the request</div></a><a href="/en/blog/specs-rules-skills/"><div class="k">Context</div><div class="t">Specs, bible, rules and skills</div><div class="d">Where a prompt lives beyond one chat</div></a><a href="/en/blog/ai-in-code-harness-and-tools/"><div class="k">Engineering</div><div class="t">AI in code</div><div class="d">The harness and three groups of tools</div></a><a href="/en/blog/chatgpt-enterprise-usage-report/"><div class="k">Report</div><div class="t">ChatGPT Enterprise usage report</div><div class="d">Who in the company uses what</div></a></div></section><footer>The prompts are templates: fill in what is in square brackets. The techniques follow the official Anthropic, OpenAI and Google guides; the source is behind the icon next to each claim. OpenAI Help Center and Google guide quotes are paraphrased.</footer></div>]]></content:encoded></item>
</channel></rss>
