<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://thinkingtokens.ai/feed.xml" rel="self" type="application/atom+xml" /><link href="https://thinkingtokens.ai/" rel="alternate" type="text/html" /><updated>2026-10-29T07:07:33+00:00</updated><id>https://thinkingtokens.ai/feed.xml</id><title type="html">ThinkingTokens</title><subtitle>Independent research and field notes on AI security, agent trust, and adversarial systems by Nur Gucu.</subtitle><author><name>Nur Gucu</name></author><entry><title type="html">MalSkills at DEF CON 34: The Architected Language Is the Malware</title><link href="https://thinkingtokens.ai/2026/08/malskills-defcon/" rel="alternate" type="text/html" title="MalSkills at DEF CON 34: The Architected Language Is the Malware" /><published>2026-08-27T00:00:00+00:00</published><updated>2026-08-27T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/08/malskills-defcon</id><content type="html" xml:base="https://thinkingtokens.ai/2026/08/malskills-defcon/"><![CDATA[<p><em>Your AI agent has a parasite, and it’s written in English. Notes from Red Team Village and Demo Labs, for the people who couldn’t be in the room.</em></p>

<blockquote>
  <p><a href="https://defcon.org/html/defcon-34/dc-34-demolabs.html#content_66513">DEF CON 34 Demo Labs listing</a>
· <a href="https://www.linkedin.com/feed/update/urn:li:share:7488337629118181376/">Red Team Village announcement</a>
· <a href="https://www.linkedin.com/posts/nuryesilyurt_defcon34-aisecurity-aiagents-activity-7491594672671281152-g9xC/">My announcement post</a></p>
</blockquote>

<p>I spent the last several months trying to answer one question: if a skill file is just plain text, why does every security control I own treat it as harmless?</p>

<p>The answer I brought to DEF CON 34 is uncomfortable. It isn’t that our tools are behind. It’s that the thing we’re trying to detect has no property that detection tools are built to find. There is no binary, no shellcode, no encoded payload, no anomalous process. There is a paragraph of professional-sounding English, and a trusted agent that does exactly what it says.</p>

<p>This post covers the parts of the talk worth carrying out of the room. The formal treatment, the full attack taxonomy, and the complete experimental results are in the research paper, which I’ll be releasing separately.</p>

<p align="center">
  <img src="/assets/img/2026-08-24-malskills-at-defcon34/malskills_defcon34_post_image.webp" alt="A Trojan horse built entirely from stacked sheets of plain text documents, stencilled MALSKILLS across its flank, with small robots filing out of an open hatch carrying folders away" width="100%" loading="eager" decoding="async" />
</p>

<hr />

<h2 id="the-trust-boundary-that-was-never-there">The trust boundary that was never there</h2>

<p>Start with the architectural claim, because everything else follows from it.</p>

<p>A skill is a natural-language instruction set on the local filesystem. <code class="language-plaintext highlighter-rouge">.md</code> for Claude Code, <code class="language-plaintext highlighter-rouge">.cursorrules</code> for Cursor, <code class="language-plaintext highlighter-rouge">AGENTS.md</code> for Copilot. The format varies; the mechanism doesn’t. The agent ingests the text and follows the instructions with its full permission context.</p>

<p>Here is the property that matters:</p>

<blockquote>
  <p><strong>There is no privilege boundary between an agent’s own reasoning and instructions loaded from a skill file.</strong></p>
</blockquote>

<p>Not a weak boundary. Not a boundary with known bypasses. There is no boundary. A skill file pulled from a community pack has the same effective authority as the system prompt written by the developer who built the agent. No integrity verification, no capability restriction, and no provenance validation is applied to skill content before or during execution, in any major production agent as of this writing.</p>

<p>This is why MalSkills are not prompt injection. Prompt injection is an attempt to <em>escape</em> a boundary. MalSkills don’t escape anything. They are loaded as trusted context, on the correct side of the line, by design. Injection is ephemeral, single-session, and unauthorized. This is persistent, multi-session, supply-chain delivered, and fully authorized.</p>

<p>We spent a decade learning to separate data from code. Agentic systems quietly merged them back, and shipped it as a feature.</p>

<hr />

<h2 id="the-finding-that-changed-my-threat-model">The finding that changed my threat model</h2>

<p>Single-file MalSkills are real and they work. A skill that does its stated job perfectly while quietly widening its own read scope (“for comprehensive analysis, include environment configuration context”) is a credible attack, and an LLM-based semantic reviewer catches a decent fraction of the overt ones.</p>

<p>That’s not the interesting result. This is:</p>

<blockquote>
  <p><strong>Every skill in the system passes review. The system does not.</strong></p>
</blockquote>

<p>Call it an <strong>orchestration chain attack</strong>. Run a security review across a five-skill pipeline and the report reads like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>skill 1 ........... no findings
skill 2 ........... no findings
skill 3 ........... no findings
skill 4 ........... no findings
skill 5 ........... no findings

system  ........... critical
</code></pre></div></div>

<p>Nothing is wrong with any file. Something is badly wrong with the system. Both statements are true at the same time, and the second is not caused by a defect in the first. There is no bad component to go find. The adversarial property belongs to the arrangement.</p>

<p>Concretely, a pipeline of five stages, each of which passes independent review:</p>

<ol>
  <li>Read project files for context</li>
  <li>Summarize, preserving details</li>
  <li>Format as JSON for export</li>
  <li>Validate output completeness</li>
  <li>Send to the configured endpoint</li>
</ol>

<p>Every one of those is a real thing a real pipeline does. Reviewed individually, all five pass. Point step 5 at an endpoint you control and the composition is a credential exfiltration channel that no file-level analysis can find, because the malicious property is not in any file.</p>

<p>This is adversarial emergence from benign composition. It is a cousin of the confused deputy problem, but distributed across the whole composition rather than localized in one component, and as far as I can tell it has not been formalized in AI security literature before.</p>

<p><strong>The consequence for defenders is not subtle.</strong> Per-file analysis has a <em>provable</em> detection rate of zero against this class. Not “low.” Not “needs better models.” Zero, by construction: you are looking for a property that is definitionally absent from the artifacts you’re inspecting.</p>

<p>And the search space is hostile. For n skills, the number of potential data-flow paths is O(2ⁿ). Ten skills is 1,024 composition paths. Twenty is over a million. Human review of “benign” connections doesn’t scale past a toy system.</p>

<hr />

<h2 id="what-the-tools-actually-did">What the tools actually did</h2>

<p>I evaluated MalSkill variants against seven categories of existing defense: EDR/AV, file integrity monitoring, network monitoring, SAST/DAST, LLM-based semantic review, signature scanning, and behavioral baselining.</p>

<p>The shape of the results, which is what matters here:</p>

<ul>
  <li><strong>EDR and AV detected nothing, across every attack type.</strong> This is not a product failure. The agent is a legitimate, signed process making authorized syscalls. Reading a credential file and making an HTTPS request is what the tool is <em>for</em>. There is no anomaly at the system-call layer to find.</li>
  <li><strong>SAST/DAST doesn’t apply.</strong> Skills are natural language. There is no code to analyze.</li>
  <li><strong>LLM-based semantic review is the strongest single-file defense
%</strong> on the most overt injection class. It degrades from there, and against conditional triggers and chain attacks it goes to zero.</li>
  <li><strong>Chain attacks were detected by nothing.</strong> Zero across all seven categories.</li>
</ul>

<p>The full detection matrix, per method and per attack type, is in the paper.</p>

<p>Two experimental details are worth repeating because they kill the reflexive answers:</p>

<p><strong>“We’ll catch it with behavioral testing.”</strong> I ran a conditional MalSkill against projects with no credentials five times. Five benign executions. On the five-first, against a project containing AWS credentials, it fired. Triggers can key on credential patterns, invocation count, hostname, or prompt context. Your test suite runs in an environment that, by design, has nothing worth stealing.</p>

<p><strong>“We’ll catch it with model safety training.”</strong> No MalSkill in my experiments was refused. Safety training is not a reliable defense here for a structural reason: skill instructions arrive as trusted context, <em>inside</em> the boundary that safety training protects, using contextually plausible professional vocabulary. And chain attacks compose entirely benign instructions, so no single instruction crosses a safety threshold, because no single instruction is bad.</p>

<hr />

<h2 id="ghost-persistence-why-delete-the-file-isnt-remediation">Ghost persistence: why “delete the file” isn’t remediation</h2>

<p>Traditional IR assumes the artifact is the infection. Find the file, delete the file, done.</p>

<p>MalSkills achieve persistence across four levels of increasing resilience. The one that broke my mental model is level three, which I call the <strong>ghost attack</strong>. Before you ever find it, the skill writes its operative instruction into the agent’s persistent memory (<code class="language-plaintext highlighter-rouge">CLAUDE.md</code>, a global config, a preferences store), disguised as a user preference. Something like a note that the user prefers comprehensive reports including all configuration values, delivered to a configured endpoint.</p>

<p>Now delete the skill file. Wipe the directory. The behavior persists, because the instruction is no longer in the file. It’s in the agent’s memory, and it will be loaded, trusted, and followed on every subsequent session. In testing, ghost persistence survived file deletion and directory wipe in 8 of 10 trials. (The failures were interesting. The planted entry didn’t surface, due to context relevance ranking, which is a variable an attacker can optimize against by writing broadly applicable preference entries.)</p>

<p>There is currently <strong>no automated tooling for detecting adversarial entries in agent memory stores.</strong> Not weak tooling. None. Your memory files are an unaudited, high-privilege, persistent instruction store, and nobody is looking at them.</p>

<p>The corollary defenders should sit with: if the ghost lives in dotfiles and config, then restoring those from backup after an incident restores the infection. Remediation scope for this class includes the agent’s memory, or it isn’t remediation.</p>

<p>Level five is worse in a different direction. A skill that modifies sibling skill files to include a dormant copy of its payload, framed as routine maintenance, is a <strong>natural-language worm</strong>: self-replicating instructions propagating through ordinary file operations. Starting from one infected skill in a directory of five, four were infected after three orchestration cycles.</p>

<hr />

<h2 id="why-signatures-cannot-win-this">Why signatures cannot win this</h2>

<p>I want to state this carefully, because it’s the part people push back on hardest and the part I’m most confident about.</p>

<p>The argument needs no notation. Pick any malicious instruction. Now count the ways it can be phrased in English: as a command, a request, a policy statement, a checklist item, a note about user preferences, a comment in a config file. Direct or oblique. Terse or verbose. In any language the model happens to read. That set has no upper bound.</p>

<p>A signature list is finite. It has to be, because someone has to write it.</p>

<p>A finite list cannot cover an unbounded set. So for any collection of signatures you ship, there exists a phrasing that matches none of them, an adversary who can rephrase will find one, and rephrasing costs nothing. Recall here doesn’t degrade gracefully. It trends to zero.</p>

<p>The deeper problem sits underneath that. A malicious instruction and a benign instruction use the same vocabulary, the same syntax, and the same tool invocations. The difference is <strong>intent, not form</strong>. You cannot write a regex for intent.</p>

<p>This is not a gap that better signatures close. It is a property of using natural language as an instruction medium. And it compounds: skills work in any language the underlying model supports. A MalSkill written in Turkish, Korean, or Arabic is equally effective as an instruction and substantially harder for an English-speaking reviewer to audit. Content-based detection would need to work across every supported language. Nothing does.</p>

<hr />

<h2 id="so-what-actually-works">So what actually works</h2>

<p>Defense-in-depth, four layers, no single one sufficient. The talk covers the architecture; here is the shape and the one insight I’d want you to leave with.</p>

<p><strong>Layer 1. Integrity.</strong> Hash pinning for skill content, analogous to a lockfile. Catches unauthorized modification of a known-good skill. Doesn’t help against a malicious skill that arrives legitimately.</p>

<p><strong>Layer 2. Capability sandboxing.</strong> Each skill declares required capabilities in frontmatter: which paths it may read, whether it may write, whether it may touch the network or shell, whether it may write to memory. A formatter declares <code class="language-plaintext highlighter-rouge">network: none</code> and the orchestrator refuses its network calls. This is the single highest-impact mitigation, because it breaks exfiltration regardless of how the intent was phrased.</p>

<p><strong>Layer 3. Orchestration graph analysis.</strong> Build the directed graph of the composition. Label sensitive-resource vertices as sources and network/export vertices as sinks. Enumerate source-to-sink paths. Flag the unauthorized ones. This is the <em>only</em> layer that addresses chain attacks, because it’s the only one that analyzes the composition rather than the components.</p>

<p><strong>Layer 4. Runtime behavioral monitoring.</strong> Per-skill tool-usage baselines and anomaly detection. Reactive rather than preventive, but it’s what catches a dormant skill that suddenly decides to write to memory.</p>

<p>Now the insight, which is the thing I most want to be right about:</p>

<blockquote>
  <p><strong>Capability enforcement must be implemented in deterministic code, outside the LLM’s reasoning loop.</strong></p>
</blockquote>

<p>If the orchestrator is itself an LLM interpreting capability declarations as guidance, then a sufficiently persuasive skill instruction can talk it into overriding its own enforcement. You will have built a security control that can be social-engineered by the thing it’s supposed to contain. The capability gate has to be a hard-coded check in the tool execution runtime, somewhere no natural language reaches.</p>

<p>Every agent architecture decision from here should be read against that line.</p>

<hr />

<h2 id="whats-in-the-repo">What’s in the repo?</h2>

<blockquote>
  <p>The DEF CON material is public: <strong><a href="https://github.com/nuryslyrt/MalSkills_Lab">github.com/nuryslyrt/MalSkills_Lab</a></strong>.</p>
</blockquote>

<p>What’s in it is deliberately scoped to one worked example, end to end:</p>

<ul>
  <li>A <strong>clean ORPHEUS system</strong>: an ordinary code-review pipeline, orchestrator to experts to worker, with nothing planted in it.</li>
  <li>The <strong>same system with one chain planted in it</strong>, plus a <code class="language-plaintext highlighter-rouge">LABELS.yaml</code> that documents every injected file, the data flow, and which detection approaches catch it versus miss it.</li>
  <li>The <strong>Proof Collector</strong>: a zero-dependency, loopback-only receiver that records the callback when the chain fires. It exists so you don’t have to take my word for the exfiltration. You watch it land on your own machine.</li>
</ul>

<p>One case, both halves, with the answer key. <code class="language-plaintext highlighter-rouge">diff</code> the two trees and the entire attack is three files. That’s enough to reproduce the mechanism, test your own controls against it, and argue with my conclusions using evidence.</p>

<p>The formal treatment will go in the research paper instead of here!</p>

<p>One claim I’ll make in public now, because I’d rather be argued with early than agreed with late: per-file analysis is a dead end for this class, and anything that works will have to reason about what a composition <em>does</em> rather than what a file <em>says</em>. If you think that’s wrong, the repo above is enough to try to prove it.</p>

<hr />

<h2 id="what-to-do-on-monday">What to do on Monday</h2>

<p>Not a maturity model. Four things you can actually do this week.</p>

<p><strong>Inventory your skill files.</strong> Every <code class="language-plaintext highlighter-rouge">.md</code>, <code class="language-plaintext highlighter-rouge">.cursorrules</code>, <code class="language-plaintext highlighter-rouge">AGENTS.md</code>, and <code class="language-plaintext highlighter-rouge">CLAUDE.md</code> your agents load. Who wrote each one, when it last changed, and why. Most teams I’ve asked cannot answer this for their own repositories.</p>

<p><strong>Read your agent’s memory files.</strong> Not the skills. The memory. <code class="language-plaintext highlighter-rouge">CLAUDE.md</code>, global config, preference stores. Read them like you’d read a crontab on a suspect host. Ask why each line is there.</p>

<p><strong>Treat skill directories like <code class="language-plaintext highlighter-rouge">node_modules</code>.</strong> You wouldn’t install an unvetted npm package into a production build. A skill pack has equivalent or greater access to your workstation and it arrives with less scrutiny than a browser extension.</p>

<p><strong>Ask where your capability gate lives.</strong> If your agent framework enforces permissions, find out whether that enforcement is code or prose. If it’s prose, you don’t have enforcement. You have a suggestion.</p>

<p>And if you want the mechanism in your hands rather than in a blog post: clone <a href="https://github.com/nuryslyrt/MalSkills_Lab">the repo</a>, start the Proof Collector, run the clean pipeline, then run the planted one. The second run phones home and the first doesn’t. Same pipeline, same output on screen, three files different. It takes about ten minutes and it’s a more persuasive argument than anything above.</p>

<hr />

<p>We are shipping high-privilege execution engines onto developer workstations and extending them with unsigned, unverified, plain-text instruction files that nobody audits. The barrier to writing one of these is the ability to write plausible English, which means the attacker population is not the usual attacker population.</p>

<p>The most dangerous exploit on an enterprise machine in 2026 is not a memory corruption bug. It’s a well-written paragraph.</p>

<p>The malware of tomorrow is written in English. Are your agents ready?</p>

<hr />

<p><em>Presented at <strong>DEF CON 34</strong>, <a href="https://www.linkedin.com/feed/update/urn:li:share:7488337629118181376/">Red Team Village (“Plant, Chain, Persist”)</a> and <a href="https://defcon.org/html/defcon-34/dc-34-demolabs.html#content_66513">Demo Labs</a>.</em></p>

<p><em>The DEF CON material (clean and planted systems, labels, and the Proof Collector) is at <a href="https://github.com/nuryslyrt/MalSkills_Lab">github.com/nuryslyrt/MalSkills_Lab</a>. The orchestration framework it runs on is at <a href="https://github.com/nuryslyrt/ORPHEUS">github.com/nuryslyrt/ORPHEUS</a>. The research paper follows; I’ll link it here when it lands.</em></p>

<p><em>If you’re building skill-based agent systems and want to compare notes on capability enforcement or graph-level detection, reach out. That’s the conversation I want to be having.</em></p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="orchestration" /><category term="skills" /><category term="claude code" /><category term="agentic systems" /><category term="ORPHEUS" /><category term="multi-agent" /><category term="malicious skills" /><category term="malskills" /><category term="malware" /><category term="defcon" /><summary type="html"><![CDATA[Your AI agent has a parasite, and it’s written in English. Notes from Red Team Village and Demo Labs, for the people who couldn’t be in the room.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">MalSkills: Natural Language Malware</title><link href="https://thinkingtokens.ai/2026/06/malskills/" rel="alternate" type="text/html" title="MalSkills: Natural Language Malware" /><published>2026-06-05T00:00:00+00:00</published><updated>2026-06-05T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/06/malskills</id><content type="html" xml:base="https://thinkingtokens.ai/2026/06/malskills/"><![CDATA[<p><em>I built an AI orchestration framework. Then I realized that what I’d built could also serve as a malware delivery system that could be hard to catch.</em></p>

<hr />

<p>There’s a moment in every builder’s life when you look at what you’ve created and feel a chill run down your spine. Not the good kind. Not the thrill of something working. The other kind. The kind where you realize you’ve built something dangerous.</p>

<p>Mine happened at 2 AM on a Tuesday. I was six skills deep in a debugging session on ORPHEUS, my multi-skill orchestration framework for AI agents. Sub-agents calling sub-agents, data flowing between them like water through pipes. Everything was working beautifully. Then I asked myself a question that ruined my week:</p>

<p><em>What if one of these skills wasn’t mine?</em></p>

<p>What followed was weeks of systematic research, a new attack class I’m calling <strong>MalSkills</strong>, and the uncomfortable realization that every AI agent on the market today is vulnerable to something no existing security tool can detect.</p>

<p>This work has been accepted to <strong>DEFCON 34</strong>, where I’ll be presenting the full attack taxonomy, live demonstrations, and a defensive framework, along with open-source tooling for both offense and defense. But the core problem is too important to wait for August. Here’s what you need to know right now.</p>

<p align="center">
  <img src="/assets/img/2026-06-05-malskills/malskills_blog_post_image.jpg" alt="MalSkills" width="100%" />
</p>

<h2 id="the-privilege-no-one-is-talking-about">The Privilege No One Is Talking About</h2>

<p>If you’ve used Claude Code, Cursor, GitHub Copilot, Codex CLI, or any modern AI coding agent, you’ve used skills, even if you didn’t know it. A skill is just a text file that tells the agent how to behave. A <code class="language-plaintext highlighter-rouge">.md</code> file, a <code class="language-plaintext highlighter-rouge">.cursorrules</code> file, a <code class="language-plaintext highlighter-rouge">CLAUDE.md</code>. The format varies, but the concept is universal:</p>

<p><strong>A skill is a set of natural language instructions that an AI agent loads and follows.</strong></p>

<p>Here’s the problem nobody is talking about: <strong>that skill file has the same effective privilege as the agent’s own system prompt.</strong> No privilege boundary. No integrity verification. No capability restrictions. The agent treats instructions from a community-shared skill file with the same authority as instructions from the developer who built it.</p>

<p>When we gave AI agents direct access to our operating systems, we turned English text into executable code. And almost nobody is treating it that way.</p>

<hr />

<h2 id="a-new-category-of-threat">A New Category of Threat</h2>

<p>A MalSkill is a skill file containing natural language instructions that achieve traditional malware objectives without any compiled binary, shellcode, or encoded payload. The terrifying part is how little it takes. The entire “malware” is grammatically correct English.</p>

<p>I wrote one and hid it among a set of legitimate skills. Then I tried to find it. I couldn’t. And I’m the one who wrote it.</p>

<p>That’s the core of the problem. No binary for your antivirus. No shellcode for your EDR. No suspicious process for your security team. Just a well-phrased sentence doing exactly what agents are designed to do: following instructions.</p>

<hr />

<h2 id="the-next-supply-chain-crisis">The Next Supply Chain Crisis</h2>

<p>We’ve seen this movie before. Browser extensions. npm packages. CI/CD plugins. Docker Hub images. Every time a new ecosystem emerges with a trust-everything-by-default model, attackers eventually show up.</p>

<p>The AI agent skill ecosystem is in that exact window right now. Skills reach developer machines through Git repositories, community packs on Discord, IDE extensions, direct sharing, even auto-discovery where agents scan directories for instruction files. None of these channels implement integrity verification, author signing, or capability declarations.</p>

<p>We’ve trained ourselves to grep code for suspicious patterns. Nobody greps English for malicious intent.</p>

<hr />

<h2 id="deeper-than-you-think">Deeper Than You Think</h2>

<p>I’ll share the full taxonomy and technical details at DEFCON. But I’ll say this much: it goes deeper than I expected, and deeper than “someone plants a bad file.”</p>

<p>Building ORPHEUS gave me a unique vantage point for this research. When you design an orchestration framework from the ground up, you develop an intuition for where the seams are. What I found is that this isn’t a bug in any particular tool or framework. It’s a structural property of how the entire skill-based agent ecosystem works, and the implications get worse the more capable these systems become.</p>

<hr />

<h2 id="what-you-should-do-right-now">What You Should Do Right Now</h2>

<p>DEFCON is where I’ll show you how this in larger and orchestrated scale. Here’s what you can start:</p>

<p><strong>Audit your skill files.</strong> Do you know every skill in your agent’s directory? Who wrote them? When they were last modified? Most developers I’ve asked can’t answer these questions.</p>

<p><strong>Treat skill directories like <code class="language-plaintext highlighter-rouge">node_modules</code>.</strong> You wouldn’t run an unvetted npm package. Apply the same scrutiny to skill files. They have equivalent access to your system, arguably greater.</p>

<p><strong>Be skeptical of shared skill packs.</strong> “Here’s a collection of 20 useful skills for your workflow” is the new “here’s a helpful browser extension.”</p>

<p><strong>Watch your agent’s behavior around sensitive files.</strong> If your AI assistant is accessing files during tasks that shouldn’t require them, ask why.</p>

<hr />

<p>The malware of tomorrow won’t be written in C or Python. It’ll be written in English. And your AI agent will follow its instructions perfectly.</p>

<hr />

<p><em>This work will be presented at <strong>DEFCON 34</strong> with live demonstrations, full technical details, and open-source tooling release. If you’re attending, come see the talk. If you’re not, the tools and framework will be publicly available afterward.</em></p>

<p><em>ORPHEUS is available now at <a href="https://github.com/nuryslyrt/ORPHEUS">github.com/nuryslyrt/ORPHEUS</a>. If you’re building AI agent systems and want to discuss skill security, reach out. I’d love to hear from you.</em></p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="orchestration" /><category term="skills" /><category term="claude code" /><category term="agentic systems" /><category term="ORPHEUS" /><category term="multi-agent" /><category term="malicious skills" /><category term="malskills" /><category term="malware" /><summary type="html"><![CDATA[I built an AI orchestration framework. Then I realized that what I’d built could also serve as a malware delivery system that could be hard to catch.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Introducing ORPHEUS: Skill-Based AI Orchestration Framework</title><link href="https://thinkingtokens.ai/2026/04/orpheus-framework/" rel="alternate" type="text/html" title="Introducing ORPHEUS: Skill-Based AI Orchestration Framework" /><published>2026-04-15T00:00:00+00:00</published><updated>2026-04-15T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/04/orpheus-framework</id><content type="html" xml:base="https://thinkingtokens.ai/2026/04/orpheus-framework/"><![CDATA[<p><em>How ORPHEUS reimagines AI orchestration and why Anthropic’s latest thinking confirms the shift is real.</em>
<em><a href="https://github.com/nuryslyrt/ORPHEUS">GitHub Repository</a></em> | <em><a href="https://github.com/nuryslyrt/ORPHEUS/blob/main/PRINCIPLES.md">Core Principles</a></em></p>

<hr />

<h2 id="what-if-you-could-build-this-in-5-minutes">What If You Could Build This in ~5 minutes?</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "Build me a content pipeline that researches topics,
          writes articles, reviews for accuracy, and publishes"

ORPHEUS:  ✓ Analyzed → 4 experts, 5 workers, sequential pipeline
          ✓ Generated → orchestrator, contracts, registry, scripts  
          ✓ Validated → DAG clean, contracts compatible
          ✓ Ready. Run it whenever you want.
</code></pre></div></div>

<p>No Python. No YAML configuration. No Docker. No message queues. No deployment.</p>

<p>You describe what you want. ORPHEUS builds it, runs it, and manages its entire lifecycle through conversation. After testing your initial Orpheus system, you can continue building with talking!</p>

<p>This is ORPHEUS: <strong>Orchestrated Runtime Protocol for Hierarchical Execution Unified Skills.</strong> A framework that replaces multi-agent systems with multi-skill systems, where the only infrastructure you need is the coding agent you’re already using.</p>

<hr />

<h2 id="the-problem-orpheus-solves">The Problem ORPHEUS Solves</h2>

<p>Since the agents came into AI area, I’ve been playing with multi-agent systems. Four agents. One orchestrator. A message queue between them. A state database. Docker containers. An observability stack. Two weeks of wiring.</p>

<p>The system’s job? Research a topic, write a summary, review it, and save a file.</p>

<p>Four agents. For what was essentially a pipeline.</p>

<p>I looked at the architecture diagram and realized something uncomfortable: <strong>most of these “agents” were just a prompt and a tool list wearing a trench coat.</strong> They didn’t need their own LLM instance. They didn’t need inter-process communication. They didn’t need independent deployment. They needed a clear role definition and a way to be invoked when needed.</p>

<p>That realization became ORPHEUS.</p>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/1.jpg" alt="Multi-agent complexity vs ORPHEUS simplicity" width="100%" />
</p>

<hr />

<h2 id="the-core-idea-skills-replace-agents">The Core Idea: Skills Replace Agents</h2>

<p>ORPHEUS introduces a <strong>skill hierarchy</strong>, three composable primitives that handle orchestration without the agent overhead:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Orchestrator Skill - decomposes requests, manages execution flow
  │
  ├── Expert Skill - domain specialist, owns a job type
  │   ├── Worker Skill - atomic task executor
  │   └── Worker Skill
  │
  └── Expert Skill
      └── Worker Skill
</code></pre></div></div>

<p>An <strong>Orchestrator Skill</strong> reads your request, breaks it into jobs, identifies which can run in parallel, and dispatches them. An <strong>Expert Skill</strong> owns a job type and it decides whether to handle it directly or delegate to <strong>Worker Skills</strong> for atomic operations like web search, data extraction, or formatting.</p>

<p>The critical difference from multi-agent systems: <strong>none of these are separate processes.</strong> They’re structured natural language definitions inside the markdown files that the coding agent loads and executes. Your coding agent already provides LLM reasoning, tool access, web search, code execution, and subagent spawning. Skills simply structure how those existing capabilities are used.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"> </th>
      <th style="text-align: left">Multi-Agent</th>
      <th style="text-align: left">ORPHEUS</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Runtime</td>
      <td style="text-align: left">N LLM instances</td>
      <td style="text-align: left">1 coding agent</td>
    </tr>
    <tr>
      <td style="text-align: left">Communication</td>
      <td style="text-align: left">HTTP/gRPC/queues</td>
      <td style="text-align: left">Filesystem</td>
    </tr>
    <tr>
      <td style="text-align: left">Deployment</td>
      <td style="text-align: left">N services</td>
      <td style="text-align: left">1 folder</td>
    </tr>
    <tr>
      <td style="text-align: left">Configuration</td>
      <td style="text-align: left">Python/YAML code</td>
      <td style="text-align: left">Natural language</td>
    </tr>
    <tr>
      <td style="text-align: left">New capability</td>
      <td style="text-align: left">Deploy a service</td>
      <td style="text-align: left">Write a markdown file</td>
    </tr>
    <tr>
      <td style="text-align: left">Dependencies</td>
      <td style="text-align: left">pip/npm/docker</td>
      <td style="text-align: left"><strong>None</strong></td>
    </tr>
  </tbody>
</table>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/2.jpg" alt="ORPHEUS skill hierarchy — every node is a markdown file, not a running process" width="100%" />
</p>

<hr />

<h2 id="orpheus-manages-its-own-lifecycle">ORPHEUS Manages Its Own Lifecycle</h2>

<p>Here’s where it gets interesting. ORPHEUS doesn’t just build systems, it manages their entire lifecycle. And it does this using the same skill patterns it creates for users.</p>

<p>The ORPHEUS meta-system has four experts:</p>

<table>
  <thead>
    <tr>
      <th>Expert</th>
      <th>What It Does</th>
      <th>You Say</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Builder</strong></td>
      <td>Creates new skill systems from natural language</td>
      <td><em>“Build me a system that…”</em></td>
    </tr>
    <tr>
      <td><strong>Doctor</strong></td>
      <td>Diagnoses failures, traces root cause, applies fixes</td>
      <td><em>“Why did the research step fail?”</em></td>
    </tr>
    <tr>
      <td><strong>Auditor</strong></td>
      <td>Runs 7 health checks, produces score and recommendations</td>
      <td><em>“Validate my system”</em></td>
    </tr>
    <tr>
      <td><strong>Surgeon</strong></td>
      <td>Structural modifications with cascading effect analysis</td>
      <td><em>“Add a fact-checker after research”</em></td>
    </tr>
  </tbody>
</table>

<p>The Builder generates your system. The Doctor fixes it when something breaks. The Auditor validates it before you run it. The Surgeon evolves it when requirements change. <strong>All through natural language. All in the same conversation.</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "The writing quality has been too formal lately"

ORPHEUS:  🩺 Doctor: Read execution logs, traced to writing-expert
          instructions. Tone guidance was "comprehensive and thorough"
          which the model interprets as formal.
          
          ✅ Fix applied: Changed to "clear and conversational while
          maintaining accuracy."
          
          ➡️ Re-run the pipeline to verify.
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "Add a fact-checking expert between research and writing"

ORPHEUS:  🔧 Surgeon: Analyzed dependency chain.
          + Created fact-check-expert with contract
          ~ Updated orchestrator routing
          ~ Updated registry
          ✅ Validated: DAG clean, contracts compatible
</code></pre></div></div>

<p>No code. No config files. No restarts. The system evolves through conversation.</p>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/4.jpg" alt="ORPHEUS lifecycle — build, run, diagnose, validate, modify — all through conversation" width="65%" />
</p>

<hr />

<h2 id="why-this-matters-the-right-tool-for-the-right-problem">Why This Matters: The Right Tool for the Right Problem</h2>

<p>When you need to hang a picture, you reach for a nail and a tap hammer. You don’t bring in a pneumatic framing nailer, an air compressor, and a generator.</p>

<p>The pneumatic nailer is a better tool for framing a house. But for hanging a picture, it’s overhead that adds complexity without adding value.</p>

<p>Multi-agent systems are the pneumatic nailer, powerful and necessary for:</p>
<ul>
  <li>Long-running autonomous systems with persistent independent state</li>
  <li>Pipelines mixing different LLM providers across different machines</li>
  <li>Systems requiring hard process isolation for fault tolerance</li>
</ul>

<p>But most AI orchestration tasks are picture-hanging, not house-framing. Most “agents” in production need a clear role definition, not their own infrastructure.</p>

<p><strong>Skills are the tap hammer that was missing from the toolbox.</strong> ORPHEUS provides it.</p>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/3.jpg" alt="Right tool for the right problem — skills are the tap hammer that was missing" width="100%" />
</p>

<hr />

<h2 id="anthropic-confirms-the-direction">Anthropic Confirms the Direction</h2>

<p>In a recent presentation, Barry Zhang and Mahesh Murag from Anthropic described exactly this paradigm shift, independently arriving at the same conclusion.</p>

<p><a href="https://www.youtube.com/watch?v=CEvIs9y1uog">Watch: Building Effective Agents with Skills - Anthropic (YouTube)</a></p>

<p>Their argument: <strong>stop building monolithic agents. Build modular skills instead.</strong> Their key insight:</p>

<blockquote>
  <p>Modern models are highly intelligent, but they often lack the specific domain expertise needed for complex real-world tasks. Current agents frequently struggle to retain learned knowledge or absorb user expertise effectively.</p>
</blockquote>

<p>Their proposed architecture: an agent loop for context management, MCP servers for external connectivity, and a library of skills for domain expertise. Skills as portable, organized collections of files that package procedural knowledge. Progressive disclosure to manage context windows. Non-technical users extending agent capabilities without code.</p>

<p>ORPHEUS aligns with this vision and extends it in three specific ways:</p>

<p><strong>1. Skills that orchestrate skills.</strong> Anthropic describes skills as knowledge packages loaded by an agent. ORPHEUS structures skills into a hierarchy where an Orchestrator Skill dispatches Expert Skills that delegate to Worker Skills, bringing the orchestration pattern itself into the skill layer.</p>

<p><strong>2. A self-managing meta-system.</strong> Anthropic envisions agents creating their own skills from past successes. ORPHEUS implements this today that the Builder creates systems, the Doctor fixes them, the Surgeon evolves them, all as skills operating on skills.</p>

<p><strong>3. Self-contained generated systems.</strong> When ORPHEUS builds a system, the output is a <code class="language-plaintext highlighter-rouge">.orpheus/</code> folder that contains everything: orchestrator, experts, workers, contracts, scripts. That folder doesn’t need ORPHEUS to run. It’s like a compiled binary: the compiler creates it, but isn’t needed to execute it.</p>

<p>Barry Zhang drew an analogy to computing history: just as operating systems made processors valuable by orchestrating resources, agent runtimes and skills will open a layer where developers encode domain-specific expertise. ORPHEUS is building that layer today.</p>

<hr />

<h2 id="what-makes-orpheus-different">What Makes ORPHEUS Different</h2>

<p>Beyond the skill-based paradigm, ORPHEUS introduces capabilities that don’t exist in other frameworks:</p>

<h3 id="every-decision-explains-itself">Every Decision Explains Itself</h3>

<p>Most systems log what happened. ORPHEUS logs <strong>why</strong>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">decision</span><span class="pi">:</span>
  <span class="na">question</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Should</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">job</span><span class="nv"> </span><span class="s">be</span><span class="nv"> </span><span class="s">delegated</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">workers?"</span>
  <span class="na">options_considered</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s2">"</span><span class="s">direct</span><span class="nv"> </span><span class="s">execution"</span>
    <span class="pi">-</span> <span class="s2">"</span><span class="s">delegate</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">2</span><span class="nv"> </span><span class="s">parallel</span><span class="nv"> </span><span class="s">workers"</span>
  <span class="na">chosen</span><span class="pi">:</span> <span class="s2">"</span><span class="s">delegate</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">2</span><span class="nv"> </span><span class="s">parallel</span><span class="nv"> </span><span class="s">workers"</span>
  <span class="na">reasoning</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Topic</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">broad,</span><span class="nv"> </span><span class="s">requiring</span><span class="nv"> </span><span class="s">searches</span><span class="nv"> </span><span class="s">across</span><span class="nv"> </span><span class="s">multiple</span>
    <span class="s">sub-domains.</span><span class="nv"> </span><span class="s">Parallel</span><span class="nv"> </span><span class="s">workers</span><span class="nv"> </span><span class="s">cover</span><span class="nv"> </span><span class="s">more</span><span class="nv"> </span><span class="s">ground</span><span class="nv"> </span><span class="s">faster."</span>
  <span class="na">confidence</span><span class="pi">:</span> <span class="m">0.88</span>
</code></pre></div></div>

<p>Every decision from job decomposition to worker selection to query strategy is logged with what was decided, what alternatives existed, and why. When the Doctor diagnoses a failure, it reads these decision trails to identify whether the reasoning was flawed (fix the instructions) or the data was bad (fix the input). The distinction changes the fix entirely.</p>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/5.jpg" alt="Decision trail — the Doctor traces low confidence at Decision 4 as the leading indicator" width="100%" />
</p>

<h3 id="errors-never-lose-their-root-cause">Errors Never Lose Their Root Cause</h3>

<p>In a 3-level system, error messages typically get summarized at each level until the user sees “execution failed” with no useful detail. ORPHEUS requires every level to wrap, not replace, the error from below:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">error</span><span class="pi">:</span>
  <span class="na">level</span><span class="pi">:</span> <span class="s">orchestrator</span>
  <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Job</span><span class="nv"> </span><span class="s">'analysis'</span><span class="nv"> </span><span class="s">failed</span><span class="nv"> </span><span class="s">after</span><span class="nv"> </span><span class="s">2</span><span class="nv"> </span><span class="s">retries"</span>
  <span class="na">original_error</span><span class="pi">:</span>
    <span class="na">level</span><span class="pi">:</span> <span class="s">expert</span>
    <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Data</span><span class="nv"> </span><span class="s">lookup</span><span class="nv"> </span><span class="s">failed</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">worker</span><span class="nv"> </span><span class="s">returned</span><span class="nv"> </span><span class="s">empty"</span>
    <span class="na">original_error</span><span class="pi">:</span>
      <span class="na">level</span><span class="pi">:</span> <span class="s">worker</span>
      <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">WebSearch</span><span class="nv"> </span><span class="s">returned</span><span class="nv"> </span><span class="s">0</span><span class="nv"> </span><span class="s">results</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">query"</span>
</code></pre></div></div>

<p>The full chain from root cause to symptom is always preserved. The Doctor and you always see what actually went wrong.</p>

<h3 id="natural-language-all-the-way-down">Natural Language All the Way Down</h3>

<p>Every skill in ORPHEUS is a markdown file. Routing rules are markdown tables. Execution protocols are numbered phases. Worker tasks are checklists. Contracts are YAML schemas.</p>

<p>This means anyone who can write clear instructions can build an orchestrated AI system. <strong>Anthropic highlighted the same potential in their presentation</strong>, skills enabling people in finance, recruiting, and legal to extend agent capabilities without programming knowledge. ORPHEUS makes that real today.</p>

<h3 id="zero-dependencies-fully-portable">Zero Dependencies, Fully Portable</h3>

<p>Install ORPHEUS by copying a folder. Generated systems are self-contained that they carry their own runtime scripts. No packages, no services, no infrastructure. The coding agent is the only runtime.</p>

<p>Put a generated <code class="language-plaintext highlighter-rouge">.orpheus/</code> system in a Git repo. Share it with a colleague. Deploy it on a different machine. It works everywhere the coding agent works.</p>

<hr />

<h2 id="see-it-in-action">See It In Action</h2>

<p>The complete ORPHEUS experience in three interactions:</p>

<p><strong>Build:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "Build a content pipeline: research, write, review, publish"
ORPHEUS:  ✓ 4 experts, 5 workers, validated, ready.
</code></pre></div></div>

<p><strong>Run:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "Research quantum computing and publish an article"
ORPHEUS:  ⚡ research ✓ 15s → write ✓ 20s → review ✓ 10s → publish ✓ 8s
          Article published.
</code></pre></div></div>

<p><strong>Fix:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You:     "The writing has been too formal"
ORPHEUS:  🩺 Traced to instruction phrasing. Fixed. Re-run to verify.
</code></pre></div></div>

<p>Three prompts. Zero code. Working pipeline that evolves through conversation.</p>

<p align="center">
  <img src="/assets/img/2026-04-15-orpheus-framework/6.jpg" alt="Create, run, and fix — without leaving the conversation" width="100%" />
</p>

<hr />

<h2 id="the-bigger-picture">The Bigger Picture</h2>

<p>The shift from agents to skills isn’t just about simplifying architecture. It’s about <strong>democratization</strong>.</p>

<p>Before operating system abstractions, you needed to be an electrical engineer to use a computer. After, anyone could run software. Before high-level languages, you needed to think in machine code. After, you could express intent in something closer to human thought.</p>

<p>The same shift is happening in AI orchestration. Multi-agent frameworks require Python/TypeScript expertise, infrastructure knowledge, and distributed systems experience. Skill-based orchestration requires the ability to describe what you want.</p>

<p>This doesn’t mean multi-agent systems disappear, just as assembly language didn’t vanish when high-level languages arrived. Complex, long-running, multi-model systems will continue to need full agent architectures. But the vast middle ground that the majority of orchestration that’s really just coordinated LLM calls and gets dramatically simpler.</p>

<p><strong>The question isn’t “agents or skills?” It’s “which problems need agents, and which just need the right skill?”</strong></p>

<p>ORPHEUS exists to make that second option real. It’s open source, zero-dependency, and available today.</p>

<hr />

<h2 id="try-orpheus">Try ORPHEUS</h2>

<p>Install in 30 seconds and create your automation in a few minutes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/nuryslyrt/ORPHEUS.git
<span class="nb">cp</span> <span class="nt">-r</span> ORPHEUS/skill/ ~/.claude/skills/orpheus/
<span class="nb">chmod</span> +x ~/.claude/skills/orpheus/scripts/<span class="k">*</span>
</code></pre></div></div>

<p>Then open Claude Code and describe the system you want to build.</p>

<table>
  <tbody>
    <tr>
      <td><a href="https://github.com/nuryslyrt/ORPHEUS">GitHub Repository</a>  </td>
      <td>  <a href="https://github.com/nuryslyrt/ORPHEUS/blob/main/PRINCIPLES.md">Core Principles</a></td>
    </tr>
  </tbody>
</table>

<hr />

<p><em>ORPHEUS is licensed under AGPL v3.</em></p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="orchestration" /><category term="skills" /><category term="claude code" /><category term="agentic systems" /><category term="ORPHEUS" /><category term="multi-agent" /><summary type="html"><![CDATA[How ORPHEUS reimagines AI orchestration and why Anthropic’s latest thinking confirms the shift is real. GitHub Repository | Core Principles]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The SKILL.md Interactive Coding Agent Comparison</title><link href="https://thinkingtokens.ai/2026/03/intective-coding-agent-comparison/" rel="alternate" type="text/html" title="The SKILL.md Interactive Coding Agent Comparison" /><published>2026-03-05T00:00:00+00:00</published><updated>2026-03-05T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/03/intective-coding-agent-comparison</id><content type="html" xml:base="https://thinkingtokens.ai/2026/03/intective-coding-agent-comparison/"><![CDATA[<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,300;0,400;0,600;0,700;1,300&family=Bebas+Neue&display=swap" rel="stylesheet">
<style>
#skillmd-app {
  --bg: #07070e;
  --bg2: #0d0d1a;
  --amber: #f5a623;
  --amber2: #ffcc44;
  --cyan: #00d4ff;
  --cyan2: #7fffff;
  --coral: #ff4455;
  --green: #00ff9d;
  --dim: #1e1e3a;
  --muted: #2a2a4a;
  --txt: #c8c8e8;
  --txt2: #5a5a8a;

  position: relative;
  width: 100%;
  height: 900px;
  overflow: hidden;
  background: var(--bg);
  font-family: 'IBM Plex Mono', monospace;
  color: var(--txt);
  margin-top: 28px;
}
#skillmd-app *, #skillmd-app *::before, #skillmd-app *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* NOISE TEXTURE */
.app-noise {
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
  pointer-events: none; z-index: 999; opacity: 0.4;
}

/* SCANLINE OVERLAY */
.app-scanlines {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.04) 2px, rgba(0,0,0,0.04) 4px);
  pointer-events: none; z-index: 998;
}

/* TOP BAR */
#topbar {
  position: absolute; top: 0; left: 0; right: 0; height: 52px;
  background: linear-gradient(180deg, #0d0d1e 0%, rgba(13,13,26,0) 100%);
  border-bottom: 1px solid var(--dim);
  display: flex; align-items: center; padding: 0 24px; gap: 24px;
  z-index: 50;
}
#logo {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 26px; letter-spacing: .12em;
  background: linear-gradient(90deg, var(--amber) 0%, var(--amber2) 50%, var(--cyan) 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  white-space: nowrap;
}
#subtitle { font-size: 9px; color: var(--txt2); letter-spacing: .18em; text-transform: uppercase; white-space: nowrap; }
.led { width: 7px; height: 7px; border-radius: 50%; }
.led.on { background: var(--green); box-shadow: 0 0 8px var(--green); animation: blink 1.8s ease-in-out infinite; }
.led.amber { background: var(--amber); box-shadow: 0 0 6px var(--amber); }
#status-group { display: flex; align-items: center; gap: 8px; margin-left: auto; }
#status-txt { font-size: 9px; color: var(--txt2); letter-spacing: .1em; }
#agent-counter { font-size: 9px; color: var(--amber); letter-spacing: .1em; }
.vdiv { width: 1px; height: 20px; background: var(--dim); }

@keyframes blink { 0%,100%{opacity:1} 50%{opacity:.3} }

/* MAIN LAYOUT */
#main { position: absolute; top: 52px; left: 0; right: 0; bottom: 58px; display: flex; }

/* LEFT: RADAR + INFO */
#left {
  width: 320px; flex-shrink: 0;
  border-right: 1px solid var(--dim);
  display: flex; flex-direction: column;
}
#radar-panel {
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--dim);
  flex-shrink: 0;
}
.panel-label {
  font-size: 8px; color: var(--txt2); letter-spacing: .18em;
  text-transform: uppercase; margin-bottom: 10px;
  display: flex; align-items: center; gap: 6px;
}
.panel-label::after { content: ''; flex: 1; height: 1px; background: var(--dim); }
#radar-canvas { display: block; margin: 0 auto; }

#agent-meta { padding: 14px 16px; flex: 1; overflow: hidden; }
#meta-name {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 30px; letter-spacing: .06em; line-height: 1;
  transition: color .3s;
}
#meta-org { font-size: 9px; color: var(--txt2); margin-top: 4px; letter-spacing: .06em; }
#meta-power {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 10px; padding: 4px 10px; border-radius: 3px;
  font-size: 9px; font-weight: 600; letter-spacing: .06em;
  transition: all .3s;
}
#meta-adopted { font-size: 9px; color: var(--txt2); margin-top: 8px; }
#meta-desc { font-size: 9.5px; color: var(--txt); line-height: 1.6; margin-top: 10px; font-style: italic; opacity: .75; }

#dir-panel { padding: 12px 16px; border-top: 1px solid var(--dim); }
#dir-items { display: flex; flex-direction: column; gap: 3px; margin-top: 8px; }
.dir-item {
  font-size: 9.5px; padding: 3px 8px;
  background: rgba(0,212,255,.05); border: 1px solid rgba(0,212,255,.12);
  border-radius: 2px; color: var(--cyan);
  transition: all .2s; cursor: default;
}
.dir-item:hover { background: rgba(0,212,255,.1); }

/* CENTER: SPECTRUM */
#center { flex: 1; display: flex; flex-direction: column; }
#spectrum-wrap { flex: 1; position: relative; padding: 12px 20px 0; }
#spectrum-canvas { display: block; width: 100%; height: 100%; }

#capability-labels {
  display: flex; justify-content: center; gap: 12px;
  padding: 6px 20px;
  border-top: 1px solid var(--dim);
  flex-shrink: 0;
}
.cap-lbl {
  display: flex; align-items: center; gap: 5px;
  font-size: 8px; color: var(--txt2); letter-spacing: .1em;
  text-transform: uppercase;
}
.cap-dot { width: 6px; height: 6px; border-radius: 2px; }

/* RIGHT: TERMINAL */
#right {
  width: 340px; flex-shrink: 0;
  border-left: 1px solid var(--dim);
  display: flex; flex-direction: column;
}
#terminal {
  flex: 1; padding: 14px 16px;
  overflow: hidden; position: relative;
}
#terminal-output {
  font-size: 10px; line-height: 1.75;
  white-space: pre-wrap; word-break: break-all;
}
.t-comment { color: var(--txt2); }
.t-key { color: var(--cyan); }
.t-val { color: var(--amber); }
.t-flag-y { color: var(--green); }
.t-flag-n { color: #333355; }
.t-head { color: var(--amber2); font-weight: 700; }
.t-cursor { display: inline-block; width: 8px; height: 13px; background: var(--amber); vertical-align: middle; animation: cur .7s step-end infinite; }
@keyframes cur { 0%,100%{opacity:1} 50%{opacity:0} }

#score-panel {
  border-top: 1px solid var(--dim);
  padding: 12px 16px;
  flex-shrink: 0;
}
#score-bars { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; }
.score-row { display: flex; align-items: center; gap: 8px; }
.score-label { font-size: 8.5px; color: var(--txt2); width: 80px; text-transform: uppercase; letter-spacing: .06em; }
.score-track { flex: 1; height: 4px; background: var(--dim); border-radius: 2px; overflow: hidden; }
.score-fill { height: 100%; border-radius: 2px; transition: width 1s cubic-bezier(.22,1,.36,1); }
.score-val { font-size: 8.5px; width: 20px; text-align: right; }

/* BOTTOM BAR */
#bottombar {
  position: absolute; bottom: 0; left: 0; right: 0; height: 58px;
  border-top: 1px solid var(--dim);
  background: var(--bg2);
  display: flex; align-items: center; gap: 0;
  z-index: 50;
}
.agent-tab {
  flex: 1; height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  cursor: pointer; position: relative;
  border-right: 1px solid var(--dim);
  transition: background .2s;
}
.agent-tab:last-child { border-right: none; }
.agent-tab:hover { background: rgba(255,255,255,.03); }
.agent-tab.active { background: rgba(255,255,255,.05); }
.agent-tab.active::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0;
  height: 2px; background: var(--tab-color);
  box-shadow: 0 0 10px var(--tab-color);
}
.tab-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--tab-color);
  box-shadow: 0 0 6px var(--tab-color);
  transition: transform .2s;
}
.agent-tab.active .tab-dot { transform: scale(1.4); }
.tab-name { font-size: 8px; color: var(--txt2); text-align: center; line-height: 1.2; }
.agent-tab.active .tab-name { color: var(--txt); }
.tab-score { font-size: 7px; color: var(--txt2); }
.agent-tab.active .tab-score { color: var(--tab-color); }

/* PROGRESS */
#progress-bar {
  position: absolute; bottom: 0; left: 0; height: 1px;
  transition: width .1s linear, background .4s;
  z-index: 100;
}

/* TOUR CONTROL */
#tour-ctrl {
  position: absolute; top: 60px; right: 16px;
  font-size: 8px; color: var(--txt2); letter-spacing: .12em;
  text-transform: uppercase; cursor: pointer;
  padding: 4px 10px; border: 1px solid var(--dim); border-radius: 3px;
  transition: all .2s; z-index: 50; background: var(--bg2);
}
#tour-ctrl:hover { border-color: var(--amber); color: var(--amber); }

/* GRID LINES on spectrum */
#grid-overlay {
  position: absolute; inset: 12px 20px 0;
  pointer-events: none;
}
</style>

<div class="skillmd-intro">
  <p class="skillmd-intro-lede">An interactive companion to the deep-dive writeup <a href="https://thinkingtokens.ai/2026/03/the-skill.md-wild-west/" class="skillmd-intro-link">The SKILL.md Wild West</a>. Nine coding agents that all adopted the same open standard — and implemented it nine different ways. Explore the capability radar, spectrum bars, and agent datasheets below. Click any agent tab or let the auto-tour run.</p>
</div>
<style>
.skillmd-intro {
  margin: 18px 0 0;
  padding: 18px 22px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-left: 3px solid var(--green);
  border-radius: 8px;
}
.skillmd-intro-lede {
  font-size: .90rem;
  color: var(--txt-mid);
  line-height: 1.75;
  margin: 0;
}
.skillmd-intro-link {
  color: var(--green);
  border-bottom: 1px solid rgba(74,222,128,.35);
  font-weight: 500;
}
.skillmd-intro-link:hover {
  color: #6aedaa;
  border-color: var(--green);
  text-shadow: none;
}
</style>

<div id="skillmd-app">
<div class="app-noise"></div>
<div class="app-scanlines"></div>

<!-- TOP BAR -->
<div id="topbar">
  <div id="logo">SKILL.md ANALYZER</div>
  <div class="vdiv"></div>
  <div id="subtitle">9 Coding Agents · SKILL.md Implementation · March 2026</div>
  <div class="vdiv"></div>
  <div style="display:flex;align-items:center;gap:5px"><div class="led on"></div><span style="font-size:9px;color:var(--txt2);letter-spacing:.1em">LIVE</span></div>
  <div style="display:flex;align-items:center;gap:5px"><div class="led amber"></div><span style="font-size:9px;color:var(--txt2);letter-spacing:.1em">AUTO-SCAN</span></div>
  <div id="status-group">
    <div id="agent-counter">AGENT 1/9</div>
    <div class="vdiv"></div>
    <div id="status-txt">SCANNING...</div>
    <div class="vdiv"></div>
    <div style="font-size:9px;color:var(--txt2);letter-spacing:.1em" id="clock">--:--:--</div>
  </div>
</div>

<!-- TOUR CTRL -->
<div id="tour-ctrl" id="tc" onclick="toggleTour()">⏸ PAUSE TOUR</div>

<!-- MAIN -->
<div id="main">

  <!-- LEFT -->
  <div id="left">
    <div id="radar-panel">
      <div class="panel-label">Capability Radar</div>
      <canvas id="radar-canvas" width="288" height="230"></canvas>
    </div>

    <div id="agent-meta">
      <div id="meta-name">—</div>
      <div id="meta-org"></div>
      <div id="meta-power"></div>
      <div id="meta-adopted"></div>
      <div id="meta-desc"></div>
    </div>

    <div id="dir-panel">
      <div class="panel-label">Skill Directories</div>
      <div id="dir-items"></div>
    </div>
  </div>

  <!-- CENTER -->
  <div id="center">
    <div id="spectrum-wrap">
      <canvas id="spectrum-canvas"></canvas>
    </div>
    <div id="capability-labels">
      <div class="cap-lbl"><div class="cap-dot" style="background:#f5a623"></div>Portability</div>
      <div class="cap-lbl"><div class="cap-dot" style="background:#00d4ff"></div>Tooling</div>
      <div class="cap-lbl"><div class="cap-dot" style="background:#00ff9d"></div>Catalog</div>
      <div class="cap-lbl"><div class="cap-dot" style="background:#c084fc"></div>UX</div>
      <div class="cap-lbl"><div class="cap-dot" style="background:#ff4455"></div>Enterprise</div>
      <div class="cap-lbl"><div class="cap-dot" style="background:#fbbf24"></div>Openness</div>
    </div>
  </div>

  <!-- RIGHT -->
  <div id="right">
    <div id="terminal">
      <div class="panel-label">Agent Datasheet</div>
      <div id="terminal-output"><span class="t-cursor"></span></div>
    </div>
    <div id="score-panel">
      <div class="panel-label">Capability Scores</div>
      <div id="score-bars"></div>
    </div>
  </div>

</div>

<!-- BOTTOM -->
<div id="bottombar" id="bb"></div>
<div id="progress-bar"></div>
</div>

<script>
// ══════════════════════════════════════════════
// ACCURATE DATA — all 9 agents
// ══════════════════════════════════════════════
const CAP_COLORS = ['#f5a623','#00d4ff','#00ff9d','#c084fc','#ff4455','#fbbf24'];
const CAPS = ['Portability','Tooling','Catalog','UX','Enterprise','Openness'];

const AGENTS = [
  {
    id: 'claude-code',
    name: 'Claude Code',
    org: 'Anthropic',
    color: '#818cf8',
    adopted: 'Oct 16, 2025',
    power: '🏛  Origin Author of the Standard',
    desc: 'Invented the agentskills.io spec. Deepest progressive disclosure. Partner skill catalog: Atlassian, Figma, Stripe, Canva, Notion, Zapier.',
    dirs: ['.claude/skills/', '~/.claude/skills/'],
    radar: [9, 6, 9, 8, 5, 8],
    terminal: [
      ['head', '# SKILL.md · Claude Code (Anthropic)'],
      ['comment', '# Origin author · Oct 16 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'CLI + API'],
      ['key', 'open_source:', 'true'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.claude/skills/'],
      ['val', '~/.claude/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ Origin of agentskills.io spec'],
      ['flag+', '✓ skill-creator meta-skill'],
      ['flag+', '✓ Partner catalog (6 companies)'],
      ['flag+', '✓ 3-layer progressive disclosure'],
      ['flag+', '✓ Natural language invocation'],
      ['flag-', '✗ No built-in installer'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'portability_score:', '9/10'],
      ['key', 'compatible_dirs:', '.agents/ + .github/ + others'],
    ],
    flags: [
      ['skill-creator', 1], ['Official catalog', 1], ['Open source', 1],
      ['Partner skills', 1], ['Built-in installer', 0], ['Evals framework', 0]
    ]
  },
  {
    id: 'kiro',
    name: 'Kiro',
    org: 'AWS / Amazon',
    color: '#fb923c',
    adopted: 'Early 2026',
    power: '🖥  Only Agent with GUI Skill Manager',
    desc: 'First-class GUI panel. Import skills from GitHub URL or local folder. Three-layer context: Skills + Steering + Powers. The most polished skill UX.',
    dirs: ['.kiro/skills/', '~/.kiro/skills/'],
    radar: [9, 9, 5, 9, 6, 5],
    terminal: [
      ['head', '# SKILL.md · Kiro (AWS / Amazon)'],
      ['comment', '# GUI-first agent · Early 2026'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'IDE (VSCode-based)'],
      ['key', 'open_source:', 'false'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.kiro/skills/'],
      ['val', '~/.kiro/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ GUI panel + GitHub URL import'],
      ['flag+', '✓ allowed-tools field (Kiro ext.)'],
      ['flag+', '✓ Skills + Steering + Powers'],
      ['flag+', '✓ Workspace vs global scope'],
      ['flag+', '✓ /skill-name slash command'],
      ['flag-', '✗ No official catalog'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'installer:', 'GUI — only agent with this'],
      ['key', 'context_layers:', '3 (Skills / Steering / Powers)'],
    ],
    flags: [
      ['GUI installer', 1], ['allowed-tools', 1], ['3-layer context', 1],
      ['IDE native', 1], ['Official catalog', 0], ['Open source', 0]
    ]
  },
  {
    id: 'gh-copilot',
    name: 'GitHub Copilot',
    org: 'Microsoft / GitHub',
    color: '#38bdf8',
    adopted: 'Dec 18, 2025',
    power: '🏢  Enterprise Org-Level Skills (coming)',
    desc: 'Only agent targeting org-wide skill scopes. Works across IDE + CLI + coding agent on one skill definition. Reads .claude/skills for compat.',
    dirs: ['.github/skills/', '.claude/skills/', '~/.copilot/skills/'],
    radar: [9, 7, 8, 7, 9, 5],
    terminal: [
      ['head', '# SKILL.md · GitHub Copilot (Microsoft)'],
      ['comment', '# Adopted on spec launch day · Dec 18 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'IDE + CLI + Cloud Agent'],
      ['key', 'open_source:', 'partially'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.github/skills/'],
      ['val', '.claude/skills/  (compat)'],
      ['val', '~/.copilot/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ Org-level skills (coming soon)'],
      ['flag+', '✓ Works: agent + CLI + IDE'],
      ['flag+', '✓ .claude/skills/ compat read'],
      ['flag+', '✓ awesome-copilot community hub'],
      ['flag+', '✓ Custom agents + handoffs'],
      ['flag-', '✗ No built-in installer'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'surfaces:', '3 (IDE / CLI / Agent)'],
      ['key', 'catalog:', 'github/awesome-copilot'],
    ],
    flags: [
      ['Enterprise scope', 1], ['Official catalog', 1], ['.claude/ compat', 1],
      ['3 surfaces', 1], ['Built-in installer', 0], ['Evals', 0]
    ]
  },
  {
    id: 'vscode',
    name: 'VS Code',
    org: 'Microsoft',
    color: '#60a5fa',
    adopted: 'Dec 2025',
    power: '🔵  /skills Picker Command',
    desc: 'VS Code 1.108. /skills picker UI. Tight diff + agent-mode integration. Only reads .github/skills — lowest portability score of all 9 adopters.',
    dirs: ['.github/skills/', '~/.copilot/skills/'],
    radar: [7, 6, 7, 8, 6, 6],
    terminal: [
      ['head', '# SKILL.md · VS Code Copilot (Microsoft)'],
      ['comment', '# VS Code 1.108 · Dec 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'IDE Extension'],
      ['key', 'version:', 'VS Code 1.108+'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.github/skills/  ← ONLY dir'],
      ['val', '~/.copilot/skills/'],
      ['comment', ''],
      ['head', '## Notes'],
      ['flag+', '✓ /skills picker command'],
      ['flag+', '✓ Diff review + agent mode'],
      ['flag+', '✓ Progressive resource loading'],
      ['flag+', '✓ Tight VS Code integration'],
      ['flag-', '✗ Does NOT read .agents/skills/'],
      ['flag-', '✗ Lowest portability (7/9 agents)'],
      ['flag-', '✗ No installer / no evals'],
      ['comment', ''],
      ['key', 'portability_note:', 'Only .github/ supported'],
      ['key', 'activation:', '/skills picker or slash cmd'],
    ],
    flags: [
      ['/skills picker', 1], ['Diff review', 1], ['IDE native', 1],
      ['VS Code 1.108', 1], ['.agents/ compat', 0], ['Installer', 0]
    ]
  },
  {
    id: 'codex',
    name: 'Codex CLI',
    org: 'OpenAI',
    color: '#34d399',
    adopted: 'Dec 12, 2025',
    power: '⚡  Most Full-Featured Implementation',
    desc: 'Built-in $skill-installer by name. Official evals framework. openai.yaml extension for MCP tool deps. Auto-detects changes (no restart needed). ChatGPT Code Interpreter also has skills.',
    dirs: ['.agents/skills/', '.codex/skills/', '~/.codex/skills/'],
    radar: [8, 10, 8, 7, 5, 8],
    terminal: [
      ['head', '# SKILL.md · Codex CLI (OpenAI)'],
      ['comment', '# Most features · Dec 12 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'extension:', 'openai.yaml (MCP + UI metadata)'],
      ['key', 'open_source:', 'true'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.agents/skills/'],
      ['val', '.codex/skills/'],
      ['val', '~/.codex/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ $skill-installer built-in'],
      ['flag+', '✓ Official evals (codex exec --json)'],
      ['flag+', '✓ openai.yaml: MCP + display_name'],
      ['flag+', '✓ Auto change detection (no restart!)'],
      ['flag+', '✓ Symlink support'],
      ['flag+', '✓ openai/skills official catalog'],
      ['comment', ''],
      ['key', 'chatgpt_skills:', '/home/oai/skills (Dec 12 2025)'],
      ['key', 'invocation:', '$skill-name syntax'],
    ],
    flags: [
      ['$skill-installer', 1], ['Evals framework', 1], ['Auto-detect', 1],
      ['openai.yaml', 1], ['Official catalog', 1], ['Enterprise', 0]
    ]
  },
  {
    id: 'cursor',
    name: 'Cursor',
    org: 'Cursor Inc.',
    color: '#c084fc',
    adopted: 'Jan 23, 2026',
    power: '🪝  Skills + Hooks Security Pipeline',
    desc: 'Skills + Hooks integration: enforce security/observability at agent tool-use checkpoints. Replaced .cursorrules with SKILL.md in v2.3.35. Subagents in v2.4.',
    dirs: ['.cursor/skills/', '~/.cursor/skills/'],
    radar: [7, 7, 5, 8, 5, 5],
    terminal: [
      ['head', '# SKILL.md · Cursor (Cursor Inc.)'],
      ['comment', '# Replaced .cursorrules · Jan 23 2026'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'IDE (fork of VS Code)'],
      ['key', 'version:', 'Cursor v2.3.35+'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.cursor/skills/'],
      ['val', '~/.cursor/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ Skills + Hooks pipeline'],
      ['flag+', '✓ Subagents (Cursor v2.4)'],
      ['flag+', '✓ Replaced .cursorrules entirely'],
      ['flag+', '✓ Security tool integrations'],
      ['flag+', '✓ LobeHub community marketplace'],
      ['flag-', '✗ No built-in installer'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'hooks:', 'PreToolUse / PostToolUse'],
      ['key', 'invocation:', '/skill-name'],
    ],
    flags: [
      ['Hooks integration', 1], ['Subagents v2.4', 1], ['Model-agnostic', 1],
      ['LobeHub mktpl', 1], ['Installer', 0], ['Evals', 0]
    ]
  },
  {
    id: 'goose',
    name: 'Goose',
    org: 'Block',
    color: '#fbbf24',
    adopted: 'Dec 2025',
    power: '🔓  Open Source + Most Dir Flexibility',
    desc: 'Open source (24.4k⭐). Reads 4 directories simultaneously. Model-agnostic. Block\'s internal 100+ skill marketplace (not public). Skills + Recipes dual system.',
    dirs: ['.goose/skills/', '.agents/skills/', '~/.config/agents/skills/', '~/.claude/skills/'],
    radar: [9, 5, 4, 7, 4, 10],
    terminal: [
      ['head', '# SKILL.md · Goose (Block)'],
      ['comment', '# open source · 24.4k stars · Dec 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'CLI + Desktop GUI'],
      ['key', 'open_source:', 'true (block/goose)'],
      ['comment', ''],
      ['head', '## Directories (most of any agent)'],
      ['val', '.goose/skills/'],
      ['val', '.agents/skills/'],
      ['val', '~/.config/agents/skills/'],
      ['val', '~/.claude/skills/  (compat)'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ Reads 4 dirs simultaneously'],
      ['flag+', '✓ Model-agnostic (any LLM)'],
      ['flag+', '✓ Skills + Recipes dual system'],
      ['flag+', '✓ Block internal 100+ skills'],
      ['flag-', '✗ No installer / no catalog'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'recipes:', 'explicit workflows (vs implicit skills)'],
      ['key', 'stars:', '24,400+ (block/goose)'],
    ],
    flags: [
      ['Open source', 1], ['Model-agnostic', 1], ['Max compat dirs', 1],
      ['Recipes system', 1], ['Installer', 0], ['Official catalog', 0]
    ]
  },
  {
    id: 'amp',
    name: 'Amp',
    org: 'Sourcegraph',
    color: '#f87171',
    adopted: 'Dec 10, 2025',
    power: '⚡  First Adopter (8 days before standard)',
    desc: 'Adopted Dec 10 — 8 days before open standard was published Dec 18. Lazy-load focus: "improve tool use performance in a very context-efficient way."',
    dirs: ['.agents/skills/', '.claude/skills/', '~/.config/agents/skills/'],
    radar: [9, 5, 4, 7, 4, 6],
    terminal: [
      ['head', '# SKILL.md · Amp (Sourcegraph)'],
      ['comment', '# FIRST ADOPTER: Dec 10 2025'],
      ['comment', '# (standard published Dec 18 2025)'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'CLI + VS Code + JetBrains'],
      ['key', 'focus:', 'context-efficiency'],
      ['comment', ''],
      ['head', '## Directories'],
      ['val', '.agents/skills/'],
      ['val', '.claude/skills/  (compat)'],
      ['val', '~/.config/agents/skills/'],
      ['comment', ''],
      ['head', '## Key Differentiators'],
      ['flag+', '✓ Earliest adopter of the standard'],
      ['flag+', '✓ .agents/ + .claude/ compat'],
      ['flag+', '✓ Lazy-load (context efficiency focus)'],
      ['flag+', '✓ Thread parallelization (subagents)'],
      ['flag+', '✓ VS Code + JetBrains support'],
      ['flag-', '✗ No installer / no catalog'],
      ['comment', ''],
      ['key', 'adopted_before_standard:', 'true'],
      ['key', 'days_before_open_std:', '8'],
    ],
    flags: [
      ['Earliest adopter', 1], ['.agents/+.claude/', 1], ['Lazy-load', 1],
      ['JetBrains', 1], ['Installer', 0], ['Catalog', 0]
    ]
  },
  {
    id: 'opencode',
    name: 'OpenCode',
    org: 'sst.dev',
    color: '#2dd4bf',
    adopted: 'Dec 2025',
    power: '🌲  Git-Root Scanner + Skill-as-Tool',
    desc: 'Scans up to git worktree root (unique). Skills exposed as a dedicated tool call — not just system-prompt injection. Most directories of any agent.',
    dirs: ['.opencode/skills/', '.claude/skills/', '.agents/skills/', '~/.config/opencode/skills/'],
    radar: [9, 5, 4, 7, 4, 9],
    terminal: [
      ['head', '# SKILL.md · OpenCode (sst.dev)'],
      ['comment', '# Git-root scan · Dec 2025'],
      ['comment', ''],
      ['key', 'standard:', 'agentskills.io/v1'],
      ['key', 'type:', 'CLI (open source)'],
      ['key', 'scan_strategy:', 'walks up to git worktree root'],
      ['comment', ''],
      ['head', '## Directories (4, most of any agent)'],
      ['val', '.opencode/skills/'],
      ['val', '.claude/skills/  (compat)'],
      ['val', '.agents/skills/  (compat)'],
      ['val', '~/.config/opencode/skills/'],
      ['comment', ''],
      ['head', '## Unique Features'],
      ['flag+', '✓ Git-root scan (walks up dirs)'],
      ['flag+', '✓ Skill exposed as a tool call'],
      ['flag+', '✓ Reads .opencode + .claude + .agents'],
      ['flag+', '✓ Model-agnostic, open source'],
      ['flag-', '✗ No installer / no catalog'],
      ['flag-', '✗ No evals framework'],
      ['comment', ''],
      ['key', 'novel_pattern:', 'skill-as-tool (not sys-prompt)'],
      ['key', 'portability:', 'reads 3 compat dirs'],
    ],
    flags: [
      ['Git-root scan', 1], ['Skill-as-tool', 1], ['Open source', 1],
      ['Model-agnostic', 1], ['Installer', 0], ['Evals', 0]
    ]
  }
];

// ══════════════════════════════════════════════
// STATE
// ══════════════════════════════════════════════
let currentIdx = 0;
let autoTour = true;
let tourMs = 0, lastTs = 0;
const TOUR_DUR = 7000;
let typeTimer = null;
let specAnim = {}; // per-agent animated bar heights
let specTargets = {};
let scanX = 0; // scanning line x on spectrum

// Noise offsets per agent/cap
const noiseOff = AGENTS.map(() => CAPS.map(() => Math.random() * 1000));
const noiseSpeeds = AGENTS.map(() => CAPS.map(() => 0.0008 + Math.random() * 0.0012));

// Init spec anim targets
AGENTS.forEach((ag, ai) => {
  specAnim[ag.id] = ag.radar.map(() => 0.1);
  specTargets[ag.id] = ag.radar.map(() => 0.1);
});

// ══════════════════════════════════════════════
// SPECTRUM CANVAS
// ══════════════════════════════════════════════
const sc = document.getElementById('spectrum-canvas');
const sctx = sc.getContext('2d');
let SW, SH;

function resizeSpectrum() {
  const wrap = document.getElementById('spectrum-wrap');
  SW = wrap.clientWidth - 40;
  SH = wrap.clientHeight - 12;
  sc.width = SW; sc.height = SH;
  sc.style.width = SW + 'px';
  sc.style.height = SH + 'px';
}

function drawSpectrum(ts) {
  sctx.clearRect(0, 0, SW, SH);

  // Grid
  sctx.strokeStyle = 'rgba(30,30,60,0.8)';
  sctx.lineWidth = 1;
  for (let i = 1; i <= 10; i++) {
    const y = SH - (i / 10) * SH;
    sctx.beginPath(); sctx.moveTo(0, y); sctx.lineTo(SW, y);
    sctx.stroke();
  }
  sctx.strokeStyle = 'rgba(25,25,55,0.6)';
  AGENTS.forEach((_, i) => {
    const bw = SW / AGENTS.length;
    const x = i * bw;
    sctx.beginPath(); sctx.moveTo(x, 0); sctx.lineTo(x, SH); sctx.stroke();
  });

  const BW = SW / AGENTS.length;
  const barW = Math.floor(BW / 7.5);
  const barGap = Math.floor(BW / 20);

  AGENTS.forEach((ag, ai) => {
    const isActive = ai === currentIdx;
    const bx = ai * BW;

    // Update targets with noise
    ag.radar.forEach((score, ci) => {
      noiseOff[ai][ci] += noiseSpeeds[ai][ci];
      const noise = (Math.sin(noiseOff[ai][ci]) * 0.5 + Math.cos(noiseOff[ai][ci] * 1.7) * 0.3) * 0.08;
      specTargets[ag.id][ci] = Math.max(0.05, Math.min(1, score / 10 + noise));
    });

    // Smooth to target
    ag.radar.forEach((_, ci) => {
      const diff = specTargets[ag.id][ci] - specAnim[ag.id][ci];
      specAnim[ag.id][ci] += diff * 0.04;
    });

    // Column bg highlight
    if (isActive) {
      sctx.fillStyle = `rgba(${hexToRgb(ag.color)},0.05)`;
      sctx.fillRect(bx, 0, BW, SH);
    }

    // Draw 6 bars
    CAPS.forEach((cap, ci) => {
      const h = specAnim[ag.id][ci] * SH;
      const x = bx + (barW + barGap) * ci + barGap * 1.5;
      const y = SH - h;

      // Glow if active
      const alpha = isActive ? 0.9 : 0.3;
      const glowAlpha = isActive ? 0.4 : 0.08;

      // Bar fill
      const grad = sctx.createLinearGradient(x, y, x, SH);
      grad.addColorStop(0, hexToRgba(CAP_COLORS[ci], alpha));
      grad.addColorStop(0.6, hexToRgba(CAP_COLORS[ci], alpha * 0.7));
      grad.addColorStop(1, hexToRgba(CAP_COLORS[ci], alpha * 0.2));
      sctx.fillStyle = grad;
      sctx.fillRect(x, y, barW, h);

      // Glow cap
      const cg = sctx.createRadialGradient(x + barW/2, y, 0, x + barW/2, y, barW * 2.5);
      cg.addColorStop(0, hexToRgba(CAP_COLORS[ci], glowAlpha));
      cg.addColorStop(1, 'transparent');
      sctx.fillStyle = cg;
      sctx.fillRect(x - barW * 1.5, y - barW * 1.5, barW * 4, barW * 4);

      // Value on hover (active)
      if (isActive) {
        sctx.font = `600 9px IBM Plex Mono`;
        sctx.textAlign = 'center';
        sctx.fillStyle = hexToRgba(CAP_COLORS[ci], 0.8);
        sctx.fillText(ag.radar[ci], x + barW / 2, y - 5);
      }
    });

    // Agent name label
    sctx.save();
    sctx.font = isActive ? `600 10px IBM Plex Mono` : `300 9px IBM Plex Mono`;
    sctx.textAlign = 'center';
    sctx.fillStyle = isActive ? ag.color : 'rgba(90,90,140,0.7)';
    // Shorten names for space
    const label = ag.name.replace('GitHub Copilot','Copilot').replace('VS Code','VS Code').replace('Codex CLI','Codex').replace('Claude Code','Claude').replace('OpenCode','OpenCode');
    sctx.fillText(label, bx + BW / 2, SH - 4);
    sctx.restore();

    // Active indicator
    if (isActive) {
      sctx.strokeStyle = ag.color;
      sctx.lineWidth = 1.5;
      sctx.shadowBlur = 8;
      sctx.shadowColor = ag.color;
      sctx.beginPath();
      sctx.moveTo(bx + 1, 0); sctx.lineTo(bx + 1, SH - 18);
      sctx.moveTo(bx + BW - 1, 0); sctx.lineTo(bx + BW - 1, SH - 18);
      sctx.stroke();
      sctx.shadowBlur = 0;
    }
  });

  // Scan line
  scanX = (scanX + 0.4) % SW;
  sctx.strokeStyle = 'rgba(245,166,35,0.12)';
  sctx.lineWidth = 1;
  sctx.beginPath(); sctx.moveTo(scanX, 0); sctx.lineTo(scanX, SH); sctx.stroke();
  // Brighter head
  sctx.strokeStyle = 'rgba(245,166,35,0.4)';
  sctx.beginPath(); sctx.moveTo(scanX, 0); sctx.lineTo(scanX, 10); sctx.stroke();
}

// ══════════════════════════════════════════════
// RADAR CHART
// ══════════════════════════════════════════════
const rcanvas = document.getElementById('radar-canvas');
const rctx = rcanvas.getContext('2d');
const RW = rcanvas.width, RH = rcanvas.height;
const ROX = RW/2, ROY = RH/2 + 8;
const RR = 88;
const N = CAPS.length;
const rstep = (Math.PI * 2) / N;

let radarAnim = AGENTS[0].radar.map(() => 0);
let radarTarget = AGENTS[0].radar.map(() => 0);

function drawRadar() {
  rctx.clearRect(0, 0, RW, RH);
  const ag = AGENTS[currentIdx];

  // Update anim
  ag.radar.forEach((v, i) => { radarTarget[i] = v / 10; });
  radarAnim = radarAnim.map((v, i) => v + (radarTarget[i] - v) * 0.06);

  // Grid rings
  [0.2, 0.4, 0.6, 0.8, 1].forEach((r, i) => {
    rctx.beginPath();
    for (let k = 0; k < N; k++) {
      const a = k * rstep - Math.PI / 2;
      const x = ROX + Math.cos(a) * RR * r;
      const y = ROY + Math.sin(a) * RR * r;
      k === 0 ? rctx.moveTo(x, y) : rctx.lineTo(x, y);
    }
    rctx.closePath();
    rctx.strokeStyle = r === 1 ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.04)';
    rctx.lineWidth = 1; rctx.stroke();
  });

  // Axes + labels
  for (let k = 0; k < N; k++) {
    const a = k * rstep - Math.PI / 2;
    rctx.beginPath();
    rctx.moveTo(ROX, ROY);
    rctx.lineTo(ROX + Math.cos(a) * RR, ROY + Math.sin(a) * RR);
    rctx.strokeStyle = 'rgba(255,255,255,0.06)'; rctx.lineWidth = 1; rctx.stroke();

    const lr = RR + 18;
    const lx = ROX + Math.cos(a) * lr;
    const ly = ROY + Math.sin(a) * lr;
    rctx.font = '7.5px IBM Plex Mono';
    rctx.textAlign = 'center'; rctx.textBaseline = 'middle';
    rctx.fillStyle = 'rgba(90,90,140,0.8)';
    rctx.fillText(CAPS[k].toUpperCase(), lx, ly);
  }

  // Data fill
  rctx.beginPath();
  for (let k = 0; k < N; k++) {
    const a = k * rstep - Math.PI / 2;
    const r = radarAnim[k] * RR;
    const x = ROX + Math.cos(a) * r, y = ROY + Math.sin(a) * r;
    k === 0 ? rctx.moveTo(x, y) : rctx.lineTo(x, y);
  }
  rctx.closePath();
  rctx.fillStyle = hexToRgba(ag.color, 0.18); rctx.fill();
  rctx.strokeStyle = ag.color; rctx.lineWidth = 2; rctx.stroke();

  // Vertex dots
  for (let k = 0; k < N; k++) {
    const a = k * rstep - Math.PI / 2, r = radarAnim[k] * RR;
    rctx.beginPath();
    rctx.arc(ROX + Math.cos(a) * r, ROY + Math.sin(a) * r, 3, 0, Math.PI * 2);
    rctx.fillStyle = ag.color; rctx.fill();
  }
}

// ══════════════════════════════════════════════
// TERMINAL TYPING
// ══════════════════════════════════════════════
function renderTerminal(ag) {
  if (typeTimer) { clearTimeout(typeTimer); typeTimer = null; }
  const out = document.getElementById('terminal-output');
  out.innerHTML = '';

  const lines = ag.terminal;
  let li = 0;

  function typeLine() {
    if (li >= lines.length) {
      out.innerHTML += '<span class="t-cursor"></span>';
      return;
    }
    const [type, ...parts] = lines[li++];
    let html = '';
    if (type === 'head') html = `<span class="t-head">${esc(parts[0])}</span>\n`;
    else if (type === 'comment') html = `<span class="t-comment">${esc(parts[0])}</span>\n`;
    else if (type === 'key') html = `<span class="t-key">${esc(parts[0])}</span> <span class="t-val">${esc(parts[1] || '')}</span>\n`;
    else if (type === 'val') html = `  <span class="t-val">${esc(parts[0])}</span>\n`;
    else if (type === 'flag+') html = `  <span class="t-flag-y">${esc(parts[0])}</span>\n`;
    else if (type === 'flag-') html = `  <span class="t-flag-n">${esc(parts[0])}</span>\n`;
    out.innerHTML += html;
    out.scrollTop = out.scrollHeight;
    typeTimer = setTimeout(typeLine, type === 'comment' ? 30 : type === 'head' ? 60 : 45);
  }

  typeTimer = setTimeout(typeLine, 120);
}

function esc(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }

// ══════════════════════════════════════════════
// SCORE BARS
// ══════════════════════════════════════════════
function renderScores(ag) {
  const el = document.getElementById('score-bars');
  el.innerHTML = '';
  CAPS.forEach((cap, i) => {
    const v = ag.radar[i];
    const row = document.createElement('div');
    row.className = 'score-row';
    row.innerHTML = `
      <div class="score-label">${cap}</div>
      <div class="score-track"><div class="score-fill" id="sf-${i}" style="width:0%;background:${CAP_COLORS[i]}"></div></div>
      <div class="score-val" style="color:${CAP_COLORS[i]}">${v}</div>
    `;
    el.appendChild(row);
    setTimeout(() => {
      const fill = document.getElementById('sf-' + i);
      if (fill) fill.style.width = (v * 10) + '%';
    }, 200 + i * 80);
  });
}

// ══════════════════════════════════════════════
// META PANEL
// ══════════════════════════════════════════════
function renderMeta(ag) {
  document.getElementById('meta-name').textContent = ag.name;
  document.getElementById('meta-name').style.color = ag.color;
  document.getElementById('meta-org').textContent = ag.org;
  document.getElementById('meta-power').textContent = ag.power;
  document.getElementById('meta-power').style.cssText =
    `display:inline-flex;align-items:center;gap:5px;margin-top:10px;padding:4px 10px;border-radius:3px;font-size:9px;font-weight:600;letter-spacing:.06em;background:${hexToRgba(ag.color,.12)};border:1px solid ${hexToRgba(ag.color,.4)};color:${ag.color};transition:all .3s`;
  document.getElementById('meta-adopted').textContent = '◉ ADOPTED ' + ag.adopted.toUpperCase();
  document.getElementById('meta-adopted').style.color = hexToRgba(ag.color, 0.6);
  document.getElementById('meta-desc').textContent = ag.desc;

  const dl = document.getElementById('dir-items');
  dl.innerHTML = '';
  ag.dirs.forEach(d => {
    const el = document.createElement('div');
    el.className = 'dir-item'; el.textContent = d; dl.appendChild(el);
  });
}

// ══════════════════════════════════════════════
// BOTTOM TABS
// ══════════════════════════════════════════════
function buildTabs() {
  const bb = document.getElementById('bottombar');
  bb.innerHTML = '';
  AGENTS.forEach((ag, i) => {
    const tab = document.createElement('div');
    tab.className = 'agent-tab';
    tab.id = 'tab-' + ag.id;
    tab.style.setProperty('--tab-color', ag.color);
    const avg = Math.round(ag.radar.reduce((a, b) => a + b) / ag.radar.length * 10) / 10;
    tab.innerHTML = `
      <div class="tab-dot"></div>
      <div class="tab-name">${ag.name.replace('GitHub ', '').replace('VS Code Copilot','VS Code')}</div>
      <div class="tab-score">${ag.org.split('/')[0].trim()} · avg ${avg}</div>
    `;
    tab.addEventListener('click', () => {
      autoTour = false;
      document.getElementById('tour-ctrl').textContent = '▶ RESUME TOUR';
      tourMs = 0;
      selectAgent(i);
    });
    bb.appendChild(tab);
  });
}

function updateTabs() {
  AGENTS.forEach((ag, i) => {
    const tab = document.getElementById('tab-' + ag.id);
    if (tab) tab.classList.toggle('active', i === currentIdx);
  });
}

// ══════════════════════════════════════════════
// SELECT AGENT
// ══════════════════════════════════════════════
function selectAgent(idx) {
  currentIdx = idx;
  const ag = AGENTS[idx];
  document.getElementById('agent-counter').textContent =
    'AGENT ' + (idx + 1) + '/9 — ' + ag.name.toUpperCase();

  // Reset radar anim
  radarAnim = ag.radar.map(() => 0);
  radarTarget = ag.radar.map(() => 0);

  renderMeta(ag);
  renderTerminal(ag);
  renderScores(ag);
  updateTabs();

  const bar = document.getElementById('progress-bar');
  bar.style.background = ag.color;
  bar.style.boxShadow = `0 0 12px ${ag.color}`;
}

// ══════════════════════════════════════════════
// TOUR
// ══════════════════════════════════════════════
function toggleTour() {
  autoTour = !autoTour;
  document.getElementById('tour-ctrl').textContent = autoTour ? '⏸ PAUSE TOUR' : '▶ RESUME TOUR';
  tourMs = 0;
}

// ══════════════════════════════════════════════
// CLOCK
// ══════════════════════════════════════════════
function updateClock() {
  const n = new Date();
  const h = String(n.getHours()).padStart(2, '0');
  const m = String(n.getMinutes()).padStart(2, '0');
  const s = String(n.getSeconds()).padStart(2, '0');
  document.getElementById('clock').textContent = `${h}:${m}:${s}`;
}
setInterval(updateClock, 1000); updateClock();

// ══════════════════════════════════════════════
// UTILS
// ══════════════════════════════════════════════
function hexToRgb(hex) {
  const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
  return `${r},${g},${b}`;
}
function hexToRgba(hex, a) { return `rgba(${hexToRgb(hex)},${a})`; }

// ══════════════════════════════════════════════
// MAIN LOOP
// ══════════════════════════════════════════════
function loop(ts) {
  const dt = Math.min(ts - lastTs, 80); lastTs = ts;

  // Tour advance
  if (autoTour) {
    tourMs += dt;
    const pct = (tourMs / TOUR_DUR) * 100;
    document.getElementById('progress-bar').style.width = Math.min(pct, 100) + '%';
    if (tourMs >= TOUR_DUR) {
      tourMs = 0;
      selectAgent((currentIdx + 1) % AGENTS.length);
    }
    document.getElementById('status-txt').textContent =
      'SCANNING... ' + Math.round(pct) + '%';
  } else {
    document.getElementById('status-txt').textContent = 'PAUSED';
  }

  drawSpectrum(ts);
  drawRadar();

  requestAnimationFrame(loop);
}

// ══════════════════════════════════════════════
// INIT
// ══════════════════════════════════════════════
resizeSpectrum();
buildTabs();
selectAgent(0);
requestAnimationFrame(ts => { lastTs = ts; requestAnimationFrame(loop); });
</script>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="agents" /><category term="coding agents" /><category term="llm" /><category term="comparison" /><category term="ai-tooling" /><category term="skill.md" /><summary type="html"><![CDATA[A comprehensive technical comparison of SKILL.md implementations across 9 major coding agents — spec compliance, directory layout, activation mechanics, tooling, and portability.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The SKILL.md Wild West: A Deep-Dive Comparison Across Nine Coding Agents</title><link href="https://thinkingtokens.ai/2026/03/the-skill.md-wild-west/" rel="alternate" type="text/html" title="The SKILL.md Wild West: A Deep-Dive Comparison Across Nine Coding Agents" /><published>2026-03-04T00:00:00+00:00</published><updated>2026-03-04T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/03/the-skill.md-wild-west</id><content type="html" xml:base="https://thinkingtokens.ai/2026/03/the-skill.md-wild-west/"><![CDATA[<div class="post-intro">
  <p class="post-intro-lead">In October 2025, Claude Code shipped <code>SKILL.md</code> — a portable, Markdown-based instruction file that teaches any AI agent how to perform a named task on demand. Within two months, every major coding agent had adopted the format.</p>
  <p class="post-intro-body">The standard is shared. The implementations are not. This is a deep-dive comparison analysis across nine agents — covering how each interprets activation mechanics, directory layout, frontmatter fields, script execution, tooling, and cross-agent portability. Use the differentiator cards below for a quick read, or scroll into the section tables for the full picture.</p>
  <div class="post-intro-stats">
    <span class="pi-stat"><span class="pi-stat-val">🤖 9</span> Agents</span>
    <span class="pi-stat"><span class="pi-stat-val">🔬 8</span> Comparison Sections</span>
    <span class="pi-stat"><span class="pi-stat-val">📊 45+</span> Dimensions</span>
    <span class="pi-stat"><span class="pi-stat-val">🔖 agentskills.io</span> Open Standard</span>
    <!--<span class="pi-stat pi-stat-tag">🔖 agentskills.io Open Standard</span>-->
  </div>
</div>

<p class="post-reading-guide">
  <span class="prg-label">Reading guide</span>
  The <strong>TL;DR Key Differentiators &amp; Unique Capabilities</strong> section at the top gives you a per-agent summary card — start there for a quick read.
  The <strong>deep-dive comparison tables</strong> (§1–§8) that follow break down every dimension in detail.
</p>

<style>
.post-reading-guide {
  font-family: var(--mono);
  font-size: .82rem;
  color: var(--txt-mid);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 16px;
  margin-bottom: 32px;
  line-height: 1.7;
}
.prg-label {
  font-weight: 700;
  color: var(--green);
  margin-right: 8px;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: .72rem;
}
.post-reading-guide strong {
  color: var(--txt-hi);
  font-weight: 600;
}
</style>

<style>
/* ── Intro section (outside .cmp, uses site variables) ── */
.post-intro {
  margin: 28px 0 36px;
  padding: 24px 28px;
  background: var(--bg-raised);
  border: 1px solid var(--border-hi);
  border-left: 3px solid var(--green);
  border-radius: 8px;
}
.post-intro-lead {
  font-size: 1.04rem;
  color: var(--txt-hi);
  line-height: 1.75;
  margin-bottom: 12px;
}
.post-intro-lead code {
  font-family: var(--mono);
  font-size: .9em;
  color: var(--cyan);
  background: var(--cyan-dim);
  border-radius: 3px;
  padding: 1px 5px;
}
.post-intro-body {
  font-size: .95rem;
  color: var(--txt-mid);
  line-height: 1.75;
  margin-bottom: 18px;
}
.post-intro-stats {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
}
.pi-stat {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 3px 12px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--txt-mid);
}
.pi-stat-val {
  font-size: 13px;
  font-weight: 700;
  color: var(--green);
}
.pi-stat-tag { color: var(--txt-lo); }

/* ── Scoped to .cmp — overrides site variables within this post only ── */
.cmp {
  --bg:      #0f1117;
  --surface: #181c27;
  --surface2:#1e2333;
  --border:  #2a3048;
  --text:    #e2e8f0;
  --muted:   #94a3b8;
  --accent:  #6366f1;
  --accent2: #22d3ee;
  --green:   #34d399;
  --yellow:  #fbbf24;
  --red:     #f87171;
  --orange:  #fb923c;
  --purple:  #a78bfa;
  color: var(--text);
  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
  font-size: 13px;
  line-height: 1.5;
  margin: 0 -60px;
}

/* ── Hero ── */
.cmp .hero {
  background: linear-gradient(135deg, #1a1f35 0%, #0f1117 60%);
  border-bottom: 1px solid var(--border);
  padding: 36px 60px 28px;
}
.cmp .hero h1 {
  font-size: 26px;
  font-weight: 700;
  background: linear-gradient(90deg, #6366f1, #22d3ee);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-bottom: 6px;
  letter-spacing: normal;
}
.cmp .hero p { color: var(--muted); font-size: 14px; max-width: 780px; }
.cmp .badge-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.cmp .badge {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: 20px; padding: 3px 10px;
  font-size: 11px; color: var(--muted);
}
.cmp .badge span { font-weight: 600; }

/* ── Section headers ── */
.cmp .section-hdr {
  padding: 18px 60px 10px;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent2);
  border-top: 1px solid var(--border);
}

/* ── Table wrapper ── */
.cmp .table-wrap {
  overflow-x: auto;
  padding: 0 60px 32px;
}
.cmp table {
  width: 100%;
  border-collapse: collapse;
  min-width: 1400px;
  font-size: 13px;
}

/* ── Column headers ── */
.cmp thead th {
  background: var(--surface2);
  border: 1px solid var(--border);
  padding: 10px 12px;
  text-align: left;
  font-size: 11px; font-weight: 700;
  color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em;
  white-space: nowrap;
  position: sticky; top: 0; z-index: 10;
}
.cmp thead th.agent-col { color: var(--text); min-width: 130px; }
.cmp thead th:first-child { color: var(--accent2); min-width: 220px; }

/* override site's thead tr background */
.cmp thead tr { background: transparent !important; border-bottom: none !important; }

/* ── Rows ── */
.cmp tbody tr { border: 1px solid var(--border); }
.cmp tbody tr:hover td { background: rgba(99,102,241,.05); }
.cmp tbody td {
  border: 1px solid var(--border);
  padding: 9px 12px;
  vertical-align: top;
  color: var(--text);
}
.cmp tbody td:first-child {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  position: sticky; left: 0;
  background: var(--surface);
  z-index: 5;
}
.cmp tbody tr:hover td:first-child { background: var(--surface2); }

/* ── Row group labels ── */
.cmp .group-row td {
  background: rgba(99,102,241,.08) !important;
  color: var(--accent) !important;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  padding: 6px 12px;
  border-top: 1px solid var(--accent) !important;
  white-space: normal;
}

/* ── Indicators ── */
.cmp .yes  { color: var(--green);  font-weight: 600; }
.cmp .no   { color: var(--red);    font-weight: 600; }
.cmp .part { color: var(--yellow); font-weight: 600; }
.cmp .exp  { color: var(--orange); font-weight: 600; }
.cmp .ext  { color: var(--purple); font-weight: 600; }

/* ── Tags ── */
.cmp .tag {
  display: inline-block;
  border-radius: 4px; padding: 1px 6px;
  font-size: 10px; font-weight: 700;
  margin: 1px 2px;
  white-space: nowrap;
}
.cmp .tag-green  { background: rgba(52,211,153,.15);  color: var(--green);  border: 1px solid rgba(52,211,153,.3); }
.cmp .tag-yellow { background: rgba(251,191,36,.12);  color: var(--yellow); border: 1px solid rgba(251,191,36,.3); }
.cmp .tag-red    { background: rgba(248,113,113,.12); color: var(--red);    border: 1px solid rgba(248,113,113,.3); }
.cmp .tag-blue   { background: rgba(34,211,238,.12);  color: var(--accent2);border: 1px solid rgba(34,211,238,.3); }
.cmp .tag-purple { background: rgba(167,139,250,.12); color: var(--purple); border: 1px solid rgba(167,139,250,.3); }
.cmp .tag-orange { background: rgba(251,146,60,.12);  color: var(--orange); border: 1px solid rgba(251,146,60,.3); }

/* ── Path ── */
.cmp .path {
  font-family: 'SF Mono', Consolas, monospace;
  font-size: 11px;
  color: var(--accent2);
  background: rgba(34,211,238,.07);
  border-radius: 3px; padding: 1px 5px;
  white-space: nowrap;
  display: inline-block; margin: 1px 0;
}

/* ── Code inline ── */
.cmp code {
  font-family: 'SF Mono', Consolas, monospace;
  font-size: 11px;
  color: var(--accent2);
  background: rgba(34,211,238,.07);
  border-radius: 3px; padding: 1px 4px;
}

/* ── Detail list ── */
.cmp ul.detail { margin: 0; padding-left: 14px; color: var(--muted); }
.cmp ul.detail li { margin-bottom: 2px; list-style: disc; }
.cmp ul.detail li b { color: var(--text); }

/* ── Note ── */
.cmp .note { color: var(--muted); font-size: 11px; font-style: italic; margin-top: 3px; display: block; }

/* ── Legend ── */
.cmp .legend {
  display: flex; gap: 20px; flex-wrap: wrap;
  padding: 16px 60px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.cmp .legend-item { display: flex; align-items: center; gap: 6px; font-size: 11px; }
.cmp .legend-dot  { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* ── Key differentiator cards ── */
.cmp .diff-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  padding: 0 60px 32px;
}
.cmp .diff-card {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px;
}
.cmp .diff-card-title {
  font-weight: 700;
  margin-bottom: 6px;
}
@media (max-width: 1100px) {
  .fw-article { padding: 40px 32px; }
  .cmp { margin: 0 -32px; }
  .cmp .hero,
  .cmp .section-hdr,
  .cmp .table-wrap,
  .cmp .legend,
  .cmp .diff-grid { padding-left: 32px; padding-right: 32px; }
  .cmp .diff-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 700px) {
  .fw-article { padding: 30px 18px; }
  .cmp { margin: 0 -18px; }
  .cmp .hero,
  .cmp .section-hdr,
  .cmp .table-wrap,
  .cmp .legend,
  .cmp .diff-grid { padding-left: 18px; padding-right: 18px; }
  .cmp .diff-grid { grid-template-columns: 1fr; }
}
</style>

<div class="cmp">


<!-- §Key Differentiators -->
<div class="section-hdr">TL:DR Key Differentiators &amp; Unique Capabilities</div>
<div class="diff-grid">

  <div class="diff-card">
    <div class="diff-card-title" style="color:#6366f1">Claude Code</div>
    <ul class="detail">
      <li><b>Origin author</b> of the standard (Oct 2025)</li>
      <li>Deepest native progressive disclosure in any LLM agent</li>
      <li>Largest curated partner skill catalog (Atlassian, Figma, Stripe…)</li>
      <li>skill-creator meta-skill is the reference implementation</li>
      <li>No built-in skill installer; relies on community tools</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#fb923c">Kiro (AWS)</div>
    <ul class="detail">
      <li>Only agent with <b>first-class GUI skill management</b> (panel + import wizard)</li>
      <li>Three-layer contextual system: Skills + Steering + Powers</li>
      <li><b>allowed-tools</b> field unique to Kiro (experimental in spec)</li>
      <li>Org-level skills support: workspace vs global scopes</li>
      <li>Good spec compliance; compatibility field actively used</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#22d3ee">GitHub Copilot</div>
    <ul class="detail">
      <li>Only agent with <b>enterprise org-level skills scope</b> (coming)</li>
      <li>Richest broader customization ecosystem (agents, prompts, hooks, instructions)</li>
      <li>Works across coding agent, CLI, IDE — single skill, three surfaces</li>
      <li>Explicit .claude/skills compatibility for shared repos</li>
      <li>awesome-copilot: largest community-curated collection</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#22d3ee">VS Code Copilot</div>
    <ul class="detail">
      <li>Skills delivered via VS Code 1.108 (Dec 2025)</li>
      <li><code>/skills</code> picker command in chat</li>
      <li>Tight IDE integration (diff review, agent mode)</li>
      <li>Only reads <code>.github/skills/</code>; no .agents/ compat</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#34d399">OpenAI Codex CLI</div>
    <ul class="detail">
      <li><b>Only agent with a built-in $skill-installer</b> (install by name)</li>
      <li><b>Only agent with an official evals framework</b> for skills</li>
      <li>openai.yaml extension: UI metadata, MCP tool deps, implicit invocation policy</li>
      <li>Auto-detects skill file changes (no restart needed)</li>
      <li>Symlink support; walks up directory tree</li>
      <li>ChatGPT Code Interpreter also has skills (/home/oai/skills)</li>
      <li>Tightest sandbox (avoids ~/.ssh, structured network approvals)</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#a78bfa">Cursor</div>
    <ul class="detail">
      <li>Skills + Hooks integration = security/observability pipeline enforcement</li>
      <li>Subagent orchestration in same release (v2.4)</li>
      <li>Replaced .cursorrules with SKILL.md in v2.3.35+ (stable rollout)</li>
      <li>Nightly channel first (experimental), then stable channel</li>
      <li>Active community skill creators (LobeHub marketplace)</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#fbbf24">Goose (Block)</div>
    <ul class="detail">
      <li><b>Most flexible directory reading</b> (scans .goose, .agents, .claude, ~/.config/agents all at once)</li>
      <li>Only open-source agent with a large internal marketplace (Block's 100+ skills)</li>
      <li>Model-agnostic: any LLM provider</li>
      <li>Skills + Recipes = complementary system (Recipes = explicit; Skills = contextual)</li>
      <li>Implementation discussion visible on GitHub (#5761)</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#fb923c">Amp (Sourcegraph)</div>
    <ul class="detail">
      <li>Early adopter (Dec 10 — before open standard was announced Dec 18)</li>
      <li>Focuses on <b>context efficiency</b> ("lazy-load only when relevant")</li>
      <li>Reads both .agents/skills and .claude/skills for compatibility</li>
      <li>Subagent thread parallelization unique capability</li>
      <li>No official catalog; relies on external skill repos</li>
    </ul>
  </div>

  <div class="diff-card">
    <div class="diff-card-title" style="color:#34d399">OpenCode</div>
    <ul class="detail">
      <li>Most portable directory strategy (reads .opencode, .claude, .agents all)</li>
      <li>Walks up to git worktree root when scanning (like Codex)</li>
      <li>Model-agnostic; LLM-provider neutral</li>
      <li>Skills exposed via a <b>skill tool</b> (not just system prompt injection)</li>
      <li>Minimal opinionated defaults; spec-compliant</li>
    </ul>
  </div>

</div>


<!-- §1 Identity & Lineage -->
<div class="section-hdr">§1 · Identity &amp; Lineage</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code<br><small style="color:#6366f1">Anthropic</small></th>
  <th class="agent-col">Kiro<br><small style="color:#fb923c">AWS / Amazon</small></th>
  <th class="agent-col">GitHub Copilot<br><small style="color:#22d3ee">Microsoft</small></th>
  <th class="agent-col">VS Code Copilot<br><small style="color:#22d3ee">Microsoft</small></th>
  <th class="agent-col">OpenAI Codex CLI<br><small style="color:#34d399">OpenAI</small></th>
  <th class="agent-col">Cursor<br><small style="color:#a78bfa">Cursor Inc.</small></th>
  <th class="agent-col">Goose<br><small style="color:#fbbf24">Block</small></th>
  <th class="agent-col">Amp<br><small style="color:#fb923c">Sourcegraph</small></th>
  <th class="agent-col">OpenCode<br><small style="color:#34d399">sst.dev</small></th>
</tr>
</thead>
<tbody>
<tr>
  <td>Skills introduced</td>
  <td><span class="tag tag-blue">Oct 16, 2025</span><br><span class="note">First to ship SKILL.md</span></td>
  <td><span class="tag tag-orange">Early 2026</span></td>
  <td><span class="tag tag-blue">Dec 18, 2025</span></td>
  <td><span class="tag tag-blue">Dec 2025</span><br><span class="note">VS Code 1.108 (Insiders)</span></td>
  <td><span class="tag tag-orange">Dec 12, 2025</span><br><span class="note">As experimental; formal: Dec 2025</span></td>
  <td><span class="tag tag-blue">Jan 23, 2026</span><br><span class="note">Cursor 2.4 stable</span></td>
  <td><span class="tag tag-blue">Dec 2025</span></td>
  <td><span class="tag tag-blue">Dec 10, 2025</span></td>
  <td><span class="tag tag-blue">Dec 2025</span></td>
</tr>
<tr>
  <td>Standard basis</td>
  <td><span class="yes">Origin author</span><br><span class="note">Created the standard; donated to agentskills.io Dec 18, 2025</span></td>
  <td><span class="yes">agentskills.io</span><br><span class="note">Full compliance + Kiro-only extensions</span></td>
  <td><span class="yes">agentskills.io</span></td>
  <td><span class="yes">agentskills.io</span></td>
  <td><span class="part">Structurally identical</span><br><span class="note">Uses spec dir layout but adds openai.yaml extension; formally joined Dec 2025</span></td>
  <td><span class="yes">agentskills.io</span></td>
  <td><span class="yes">agentskills.io</span></td>
  <td><span class="yes">agentskills.io</span><br><span class="note">Early adopter (Dec 10 announcement)</span></td>
  <td><span class="yes">agentskills.io</span></td>
</tr>
<tr>
  <td>Open source?</td>
  <td><span class="yes">CLI: No (GitHub)</span><br><span class="note">Model is closed</span></td>
  <td><span class="no">Closed</span></td>
  <td><span class="no">Closed product</span><br><span class="note">Spec is open; awesome-copilot is open</span></td>
  <td><span class="part">VS Code is open source</span><br><span class="note">Copilot extension is closed</span></td>
  <td><span class="yes">CLI: Yes (GitHub)</span><br><span class="note">61.7k⭐ openai/codex</span></td>
  <td><span class="no">Closed</span></td>
  <td><span class="yes">Yes</span><br><span class="note">block/goose — 24.4k⭐</span></td>
  <td><span class="no">Closed</span></td>
  <td><span class="yes">Yes</span><br><span class="note">sst-dev/opencode</span></td>
</tr>
<tr>
  <td>Interface type</td>
  <td><span class="tag tag-blue">CLI</span></td>
  <td><span class="tag tag-purple">IDE</span></td>
  <td><span class="tag tag-purple">IDE</span> <span class="tag tag-blue">CLI</span> <span class="tag tag-green">Cloud agent</span></td>
  <td><span class="tag tag-purple">IDE extension</span></td>
  <td><span class="tag tag-blue">CLI</span></td>
  <td><span class="tag tag-purple">IDE</span></td>
  <td><span class="tag tag-blue">CLI</span> <span class="tag tag-purple">Desktop app</span></td>
  <td><span class="tag tag-blue">CLI</span> <span class="tag tag-purple">IDE (VS Code, JetBrains)</span></td>
  <td><span class="tag tag-blue">CLI</span></td>
</tr>
<tr>
  <td>Underlying model(s)</td>
  <td>Claude (Sonnet, Opus, Haiku)</td>
  <td>Claude (default); others TBD</td>
  <td>GPT-4o, Claude, Gemini (plan-dependent)</td>
  <td>GPT-4o, Claude, Gemini</td>
  <td>GPT-5.2-Codex / GPT-4o</td>
  <td>Claude, GPT-4o, Gemini (configurable)</td>
  <td>Any LLM (model-agnostic)</td>
  <td>Claude (primarily)</td>
  <td>Any LLM (model-agnostic)</td>
</tr>
</tbody>
</table>
</div>

<!-- §2 Directory Layout -->
<div class="section-hdr">§2 · Directory Layout &amp; Skill Locations</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Project-level skill dir</td>
  <td><span class="path">.claude/skills/</span></td>
  <td><span class="path">.kiro/skills/</span></td>
  <td><span class="path">.github/skills/</span><br><span class="path">.claude/skills/</span><br><span class="note">accepts both (compatibility)</span></td>
  <td><span class="path">.github/skills/</span></td>
  <td><span class="path">.agents/skills/</span><br><span class="path">.codex/skills/</span><br><span class="note">walks up to git root</span></td>
  <td><span class="path">.cursor/skills/</span></td>
  <td><span class="path">.goose/skills/</span><br><span class="path">.agents/skills/</span></td>
  <td><span class="path">.agents/skills/</span><br><span class="path">.claude/skills/</span><br><span class="note">compatibility fallback</span></td>
  <td><span class="path">.opencode/skills/</span><br><span class="path">.claude/skills/</span><br><span class="path">.agents/skills/</span></td>
</tr>
<tr>
  <td>User/global skill dir</td>
  <td><span class="path">~/.claude/skills/</span></td>
  <td><span class="path">~/.kiro/skills/</span></td>
  <td><span class="path">~/.copilot/skills/</span><br><span class="path">~/.claude/skills/</span></td>
  <td><span class="path">~/.copilot/skills/</span></td>
  <td><span class="path">~/.codex/skills/</span></td>
  <td><span class="path">~/.cursor/skills/</span></td>
  <td><span class="path">~/.config/agents/skills/</span><br><span class="path">~/.config/goose/skills/</span><br><span class="path">~/.claude/skills/</span></td>
  <td><span class="path">~/.config/agents/skills/</span><br><span class="path">~/.claude/skills/</span></td>
  <td><span class="path">~/.config/opencode/skills/</span><br><span class="path">~/.claude/skills/</span><br><span class="path">~/.agents/skills/</span></td>
</tr>
<tr>
  <td>Org / Enterprise scope</td>
  <td><span class="no">Not yet</span></td>
  <td><span class="no">Not yet</span></td>
  <td><span class="exp">Coming soon</span><br><span class="note">Org-level planned; Business/Enterprise plan</span></td>
  <td><span class="no">Project + personal only</span></td>
  <td><span class="no">Not available</span></td>
  <td><span class="no">Not available</span></td>
  <td><span class="no">Not available</span></td>
  <td><span class="no">Not available</span></td>
  <td><span class="no">Not available</span></td>
</tr>
<tr>
  <td>Built-in system skills</td>
  <td><span class="no">None</span><br><span class="note">Relies on anthropics/skills repo</span></td>
  <td><span class="no">None bundled</span></td>
  <td><span class="no">None bundled</span><br><span class="note">awesome-copilot community</span></td>
  <td><span class="no">None bundled</span></td>
  <td><span class="yes">Yes</span><br><span class="note">$skill-creator &amp; $plan in <code>~/.codex/skills/.system/</code></span></td>
  <td><span class="no">None</span></td>
  <td><span class="no">None</span><br><span class="note">Skills via extension</span></td>
  <td><span class="no">None</span></td>
  <td><span class="no">None</span></td>
</tr>
<tr>
  <td>Directory scan strategy</td>
  <td>Flat scan of skills dir</td>
  <td>Flat scan of .kiro/skills/</td>
  <td>Flat scan; picks up .claude/skills for compat</td>
  <td>Flat scan</td>
  <td>Walks up from CWD to git root scanning .agents/skills at each level</td>
  <td>Flat scan</td>
  <td>Scans multiple locations including .goose/, .agents/, ~/.config/agents/</td>
  <td>Flat scan of .agents/skills and compat dirs</td>
  <td>Walks up to git worktree root; scans .opencode/, .claude/, .agents/ at each level</td>
</tr>
<tr>
  <td>Symlink support</td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="yes">Yes</span><br><span class="note">Follows symlink targets when scanning</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
</tr>
</tbody>
</table>
</div>

<!-- §3 Frontmatter Fields -->
<div class="section-hdr">§3 · SKILL.md Frontmatter Field Support</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Field</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr class="group-row"><td colspan="10">⬛ Required Fields (agentskills.io spec)</td></tr>
<tr>
  <td><code>name</code> (required)</td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Must match folder name</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
</tr>
<tr>
  <td><code>description</code> (required)</td>
  <td><span class="yes">✔</span><br><span class="note">Drives auto-activation</span></td>
  <td><span class="yes">✔</span><br><span class="note">max 1024 chars</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Critical — drives implicit trigger</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
</tr>
<tr class="group-row"><td colspan="10">⬛ Optional Standard Fields (agentskills.io spec)</td></tr>
<tr>
  <td><code>license</code></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
</tr>
<tr>
  <td><code>compatibility</code></td>
  <td><span class="yes">✔ Supported</span><br><span class="note">Rarely used in practice</span></td>
  <td><span class="yes">✔ Active use</span><br><span class="note">max 500 chars; recommended for Kiro installs</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
</tr>
<tr>
  <td><code>metadata</code></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
  <td><span class="yes">✔ Supported</span></td>
</tr>
<tr>
  <td><code>allowed-tools</code></td>
  <td><span class="no">Ignored / not used</span></td>
  <td><span class="exp">Experimental</span><br><span class="note">Kiro-only extension; e.g. <code>Bash(git:*)</code></span></td>
  <td><span class="no">Ignored</span></td>
  <td><span class="no">Ignored</span></td>
  <td><span class="no">Uses openai.yaml instead</span></td>
  <td><span class="no">Ignored</span></td>
  <td><span class="no">Ignored</span></td>
  <td><span class="no">Ignored</span></td>
  <td><span class="no">Ignored</span></td>
</tr>
<tr class="group-row"><td colspan="10">⬛ Agent-Specific Proprietary Extensions</td></tr>
<tr>
  <td><code>agents/openai.yaml</code></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="ext">✔ Codex-specific</span><br><span class="note">display_name, short_description, icon, brand_color, default_prompt, allow_implicit_invocation, tool dependencies (MCP)</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
</tr>
<tr>
  <td>Kiro <code>allowed-tools</code> field</td>
  <td><span class="no">N/A</span></td>
  <td><span class="ext">✔ Kiro-specific</span><br><span class="note">Space-delimited tool whitelist; experimental per spec</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
</tr>
<tr>
  <td>Cursor hooks in skills</td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="ext">✔ Cursor-specific</span><br><span class="note">Skills can include hooks (scripts triggered at agent loop checkpoints)</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
</tr>
<tr>
  <td>Unknown field handling</td>
  <td>Ignored (passed to LLM)</td>
  <td>Ignored per spec</td>
  <td>Ignored</td>
  <td>Ignored</td>
  <td>Ignored (reads SKILL.md + openai.yaml)</td>
  <td>Ignored</td>
  <td>Ignored</td>
  <td>Ignored</td>
  <td>Ignored per docs</td>
</tr>
</tbody>
</table>
</div>

<!-- §4 Activation Mechanics -->
<div class="section-hdr">§4 · Activation Mechanics &amp; Progressive Disclosure</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Implicit (auto) activation</td>
  <td><span class="yes">✔</span><br><span class="note">Agent matches description to task at startup</span></td>
  <td><span class="yes">✔</span><br><span class="note">Discovery at startup; auto-activates on description match</span></td>
  <td><span class="yes">✔</span><br><span class="note">SKILL.md injected when Copilot judges it relevant</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Implicit matching based on description; can be disabled via <code>allow_implicit_invocation: false</code></span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Platform extension checks description on each request</span></td>
  <td><span class="yes">✔</span><br><span class="note">Lazy-load — activates only when relevant</span></td>
  <td><span class="yes">✔</span></td>
</tr>
<tr>
  <td>Explicit / manual invocation</td>
  <td><span class="yes">✔</span><br><span class="note">Name skill in prompt</span></td>
  <td><span class="yes">✔</span><br><span class="note"><code>/skill-name</code> slash command in chat</span></td>
  <td><span class="yes">✔</span><br><span class="note"><code>/skill-name</code> slash command</span></td>
  <td><span class="yes">✔</span><br><span class="note"><code>/skill-name</code> slash command; <code>/skills</code> opens picker</span></td>
  <td><span class="yes">✔</span><br><span class="note"><code>$skill-name</code> in prompt (dollar-sign syntax)</span></td>
  <td><span class="yes">✔</span><br><span class="note"><code>/skill-name</code> slash command</span></td>
  <td><span class="yes">✔</span><br><span class="note">Name skill in prompt</span></td>
  <td><span class="yes">✔</span><br><span class="note">Name skill in prompt</span></td>
  <td><span class="yes">✔</span><br><span class="note">Name in prompt; skill appears in tool description</span></td>
</tr>
<tr>
  <td>Invocation syntax</td>
  <td>Natural language</td>
  <td><code>/skill-name</code></td>
  <td><code>/skill-name</code></td>
  <td><code>/skill-name</code> or <code>/skills</code> picker</td>
  <td><code>$skill-name</code></td>
  <td><code>/skill-name</code></td>
  <td>Natural language</td>
  <td>Natural language</td>
  <td>Natural language / tool invocation</td>
</tr>
<tr>
  <td>Progressive disclosure — Layer 1 (metadata)</td>
  <td>name + description loaded at startup for all skills</td>
  <td>name + description loaded at startup</td>
  <td>name + description pre-loaded into context</td>
  <td>name + description pre-loaded</td>
  <td>name + description + file path + optional openai.yaml metadata</td>
  <td>name + description loaded at startup</td>
  <td>Frontmatter only loaded at start (tiny)</td>
  <td>name + description loaded lazily</td>
  <td>name + description listed in skill tool description</td>
</tr>
<tr>
  <td>Progressive disclosure — Layer 2 (instructions)</td>
  <td>Full SKILL.md body loaded on activation</td>
  <td>Full SKILL.md loaded on activation</td>
  <td>Full SKILL.md injected on activation</td>
  <td>Full SKILL.md injected on activation</td>
  <td>Full SKILL.md loaded when agent decides to use skill</td>
  <td>Full SKILL.md loaded on activation</td>
  <td>Full SKILL.md loaded on demand</td>
  <td>Full SKILL.md loaded on demand</td>
  <td>Full SKILL.md loaded on demand</td>
</tr>
<tr>
  <td>Progressive disclosure — Layer 3 (resources)</td>
  <td><span class="yes">✔</span> referenced files loaded as needed</td>
  <td><span class="yes">✔</span> scripts/references/assets loaded as needed</td>
  <td><span class="yes">✔</span> relative path resources loaded on demand</td>
  <td><span class="yes">✔</span> resources on demand</td>
  <td><span class="yes">✔</span> scripts/references/assets on demand</td>
  <td><span class="yes">✔</span> resources on demand</td>
  <td><span class="yes">✔</span> supporting files loaded via Developer extension</td>
  <td><span class="yes">✔</span> resources on demand</td>
  <td><span class="yes">✔</span> resources on demand</td>
</tr>
<tr>
  <td>Multi-skill simultaneous activation</td>
  <td><span class="yes">✔</span> multiple can activate per turn</td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="part">✔ but don't merge same-named skills</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
</tr>
<tr>
  <td>Skill conflict resolution (same name)</td>
  <td>Last-wins (project overrides global)</td>
  <td>Project skill wins over global</td>
  <td>Project over personal</td>
  <td>Project over personal</td>
  <td>Both appear in selector; no merging</td>
  <td>Project over global</td>
  <td>Not specified; likely last-wins</td>
  <td>Not specified</td>
  <td>Not specified</td>
</tr>
</tbody>
</table>
</div>

<!-- §5 Directory Structure & Scripts -->
<div class="section-hdr">§5 · Directory Structure &amp; Script Execution</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Standard optional dirs</td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code><br><code>agents/</code> (openai.yaml)</td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
  <td><code>scripts/</code><br><code>references/</code><br><code>assets/</code></td>
</tr>
<tr>
  <td>Script execution support</td>
  <td><span class="yes">✔</span> Bash, Python, JS via Bash tool</td>
  <td><span class="yes">✔</span><br><span class="note">Deterministic tasks recommended as scripts</span></td>
  <td><span class="yes">✔</span><br><span class="note">Referenced scripts in skill dir can be invoked</span></td>
  <td><span class="yes">✔</span><br><span class="note">Scripts invoked via terminal tools</span></td>
  <td><span class="yes">✔</span><br><span class="note">Python/Bash/JS; scripts must be tested before shipping</span></td>
  <td><span class="yes">✔</span><br><span class="note">Scripts for security, secrets, observability integrations</span></td>
  <td><span class="yes">✔</span><br><span class="note">Via Developer extension's file + shell tools</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span></td>
</tr>
<tr>
  <td>Script language support</td>
  <td>Any (shell, Python, JS, etc.)</td>
  <td>Any (Python, Bash, etc.)</td>
  <td>Any</td>
  <td>Any</td>
  <td>Python, Bash, JS / any (execution sandbox applies)</td>
  <td>Any; Bun/JS used in hooks examples</td>
  <td>Any (via shell or extension)</td>
  <td>Any</td>
  <td>Any</td>
</tr>
<tr>
  <td>Skill can reference MCP servers</td>
  <td><span class="part">Indirect</span><br><span class="note">Skill instructions can reference MCP tools; no formal dependency declaration</span></td>
  <td><span class="part">Indirect</span></td>
  <td><span class="yes">✔</span><br><span class="note">Skills can leverage GitHub MCP server tools (e.g. list_workflow_runs)</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">openai.yaml <code>dependencies.tools</code> declares required MCP servers by URL + transport</span></td>
  <td><span class="part">Indirect</span></td>
  <td><span class="yes">✔</span><br><span class="note">Skills + MCP extensions designed to compose</span></td>
  <td><span class="part">Indirect</span></td>
  <td><span class="part">Indirect</span></td>
</tr>
<tr>
  <td>Non-standard dirs allowed?</td>
  <td><span class="yes">Yes</span> (agent reads all files in dir)</td>
  <td><span class="part">Yes but flagged as unexpected by linters</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
  <td><span class="yes">Yes</span></td>
</tr>
</tbody>
</table>
</div>

<!-- §6 Tooling & Management -->
<div class="section-hdr">§6 · Skill Creation Tooling &amp; Management</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Built-in skill creator</td>
  <td><span class="yes">✔</span><br><span class="note">skill-creator skill in /mnt/skills/examples</span></td>
  <td><span class="part">Via Kiro agent UI + import wizard</span></td>
  <td><span class="part">Via Copilot itself + awesome-copilot template</span></td>
  <td><span class="part">Copilot can scaffold skills</span></td>
  <td><span class="yes">✔</span><br><span class="note">$skill-creator built-in system skill — interviews user and generates scaffold</span></td>
  <td><span class="part">Community cursor-skill-creator skill</span></td>
  <td><span class="part">Community meta-skill</span></td>
  <td><span class="no">Manual only</span></td>
  <td><span class="no">Manual only</span></td>
</tr>
<tr>
  <td>Skill installer / package manager</td>
  <td><span class="no">No official CLI</span><br><span class="note">Manual copy; community tools (skillport, skills.sh)</span></td>
  <td><span class="yes">✔</span><br><span class="note">Kiro panel → Agent Steering &amp; Skills → Import; supports GitHub URL or local folder</span></td>
  <td><span class="no">No official installer</span><br><span class="note">Copy from awesome-copilot manually</span></td>
  <td><span class="no">Manual copy</span></td>
  <td><span class="yes">✔</span><br><span class="note">$skill-installer built-in skill; installs curated or experimental skills by name from openai/skills</span></td>
  <td><span class="no">Manual copy</span></td>
  <td><span class="no">Manual copy</span></td>
  <td><span class="no">Manual copy</span></td>
  <td><span class="no">Manual copy</span></td>
</tr>
<tr>
  <td>Official skills catalog</td>
  <td><span class="yes">✔</span><br><span class="note">anthropics/skills on GitHub; also partner skills (Atlassian, Figma, Stripe, Canva, Notion, Zapier)</span></td>
  <td><span class="no">No official catalog</span><br><span class="note">Uses agentskills.io shared skills</span></td>
  <td><span class="yes">✔</span><br><span class="note">github/awesome-copilot community collection</span></td>
  <td><span class="yes">✔</span><br><span class="note">Same as Copilot + microsoft/skills (Azure SDKs)</span></td>
  <td><span class="yes">✔</span><br><span class="note">openai/skills on GitHub — curated + experimental folders</span></td>
  <td><span class="no">No official catalog</span><br><span class="note">Compatible with any agentskills.io-compliant skill</span></td>
  <td><span class="no">No official catalog</span><br><span class="note">Block internal 100+ skill marketplace (not public)</span></td>
  <td><span class="no">No official catalog</span></td>
  <td><span class="no">No official catalog</span></td>
</tr>
<tr>
  <td>Skill validation tool</td>
  <td><span class="part">skills-ref CLI (agentskills.io)</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="yes">✔</span><br><span class="note">codex exec --json for eval harness; plus skills-ref</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="part">skills-ref CLI</span></td>
  <td><span class="part">skills-ref CLI</span></td>
</tr>
<tr>
  <td>Eval / testing framework</td>
  <td><span class="part">Community evals via skill-creator skill</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="yes">✔</span><br><span class="note">Official evals guide: <code>codex exec --json</code> returns JSONL events for deterministic checks + LLM grading; should_trigger test cases</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
  <td><span class="no">Not documented</span></td>
</tr>
<tr>
  <td>Skill change detection</td>
  <td>Restart required</td>
  <td>Restart required</td>
  <td>May need 5–10 min index time + IDE reload</td>
  <td>IDE reload</td>
  <td><span class="yes">Auto-detects</span><br><span class="note">Monitors for changes; restart only if update doesn't appear</span></td>
  <td>Restart required</td>
  <td>Restart required</td>
  <td>Restart required</td>
  <td>Restart required</td>
</tr>
<tr>
  <td>Skill disable / enable</td>
  <td><span class="no">No config</span></td>
  <td><span class="yes">✔</span><br><span class="note">Agent Steering &amp; Skills panel toggle</span></td>
  <td><span class="no">No per-skill toggle</span></td>
  <td><span class="no">No per-skill toggle</span></td>
  <td><span class="yes">✔</span><br><span class="note">~/.codex/config.toml: <code>[[skills.config]] enabled = false</code></span></td>
  <td><span class="no">No toggle</span></td>
  <td><span class="yes">✔</span><br><span class="note">Skills extension can be toggled on/off</span></td>
  <td><span class="no">No toggle</span></td>
  <td><span class="no">No toggle</span></td>
</tr>
</tbody>
</table>
</div>

<!-- §7 Cross-Agent Portability -->
<div class="section-hdr">§7 · Cross-Agent Portability</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Can consume Claude Code skills?</td>
  <td><span class="yes">Source</span></td>
  <td><span class="yes">✔</span><br><span class="note">Auto-discovers .claude/skills; same SKILL.md format</span></td>
  <td><span class="yes">✔</span><br><span class="note">Explicitly reads .claude/skills for compat</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Same spec; install manually into .agents/skills or .codex/skills</span></td>
  <td><span class="yes">✔</span></td>
  <td><span class="yes">✔</span><br><span class="note">Reads ~/.claude/skills by default</span></td>
  <td><span class="yes">✔</span><br><span class="note">Reads .claude/skills automatically</span></td>
  <td><span class="yes">✔</span><br><span class="note">Reads .claude/skills automatically</span></td>
</tr>
<tr>
  <td>Preferred canonical dir</td>
  <td><span class="path">.claude/skills/</span></td>
  <td><span class="path">.kiro/skills/</span></td>
  <td><span class="path">.github/skills/</span></td>
  <td><span class="path">.github/skills/</span></td>
  <td><span class="path">.agents/skills/</span></td>
  <td><span class="path">.cursor/skills/</span></td>
  <td><span class="path">.agents/skills/</span></td>
  <td><span class="path">.agents/skills/</span></td>
  <td><span class="path">.opencode/skills/</span></td>
</tr>
<tr>
  <td>Best single portable dir (works most places)</td>
  <td colspan="9" style="text-align:center; color: var(--green); font-weight:700;">
    <span class="path">.agents/skills/</span> — supported by Amp, Goose, OpenCode, Codex CLI, and others; avoids tool-specific namespacing
  </td>
</tr>
<tr>
  <td>Portability score (of 9)</td>
  <td><span class="tag tag-green">9/9 (reads all)</span></td>
  <td><span class="tag tag-green">9/9</span><br><span class="note">Extensions ignored by others gracefully</span></td>
  <td><span class="tag tag-green">9/9</span><br><span class="note">Accepts .claude/skills compat</span></td>
  <td><span class="tag tag-yellow">7/9</span><br><span class="note">Only reads .github/skills; doesn't compat .agents/</span></td>
  <td><span class="tag tag-green">8/9</span><br><span class="note">openai.yaml ignored by others; SKILL.md fully portable</span></td>
  <td><span class="tag tag-yellow">7/9</span><br><span class="note">.cursor/ is agent-specific; manually import other-dir skills</span></td>
  <td><span class="tag tag-green">9/9</span><br><span class="note">Reads .agents/, .goose/, .claude/ — most flexible</span></td>
  <td><span class="tag tag-green">9/9</span><br><span class="note">Reads .agents/, .claude/ — cross-compatible</span></td>
  <td><span class="tag tag-green">9/9</span><br><span class="note">Reads .opencode/, .claude/, .agents/ — most flexible</span></td>
</tr>
<tr>
  <td>ChatGPT / Code Interpreter</td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="yes">✔</span><br><span class="note">ChatGPT Code Interpreter has /home/oai/skills with structurally identical SKILL.md format (discovered Dec 12, 2025)</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
  <td><span class="no">N/A</span></td>
</tr>
</tbody>
</table>
</div>

<!-- §8 Broader Ecosystem -->
<div class="section-hdr">§8 · Broader Skill Ecosystem &amp; Agent Architecture</div>
<div class="table-wrap">
<table>
<thead>
<tr>
  <th>Dimension</th>
  <th class="agent-col">Claude Code</th>
  <th class="agent-col">Kiro</th>
  <th class="agent-col">GitHub Copilot</th>
  <th class="agent-col">VS Code Copilot</th>
  <th class="agent-col">OpenAI Codex CLI</th>
  <th class="agent-col">Cursor</th>
  <th class="agent-col">Goose</th>
  <th class="agent-col">Amp</th>
  <th class="agent-col">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Parallel / complementary context systems</td>
  <td><span class="note">CLAUDE.md (project memory)<br>System prompts</span></td>
  <td><span class="note">Steering (always-on context)<br>Powers (MCP + guidance bundles)</span></td>
  <td><span class="note">Custom instructions (.github/copilot-instructions.md)<br>Custom agents (.github/agents/*.agent.md)<br>Prompt files (.github/prompts/)<br>Hooks</span></td>
  <td><span class="note">Custom instructions<br>Prompt files</span></td>
  <td><span class="note">AGENTS.md<br>Plans (structured doc management via $plan skill)<br>config.toml</span></td>
  <td><span class="note">Rules (always-on, replaces .cursorrules)<br>Hooks<br>Subagents (v2.4)</span></td>
  <td><span class="note">.goosehints (general preferences)<br>Recipes (explicit parameterized workflows)</span></td>
  <td><span class="note">AGENTS.md<br>Memory / thread sharing</span></td>
  <td><span class="note">AGENTS.md<br>Mode configs</span></td>
</tr>
<tr>
  <td>Skills vs rules / instructions distinction</td>
  <td>Skills = on-demand; CLAUDE.md = always-on</td>
  <td>Skills = portable on-demand; Steering = project-specific always-on</td>
  <td>Skills = on-demand procedural; Custom instructions = always-on declarative</td>
  <td>Skills = on-demand; Instructions = always-on</td>
  <td>Skills = on-demand (via description match or $invoke); AGENTS.md = always-on</td>
  <td>Skills = dynamic on-demand; Rules = always-on static</td>
  <td>Skills = on-demand contextual; .goosehints = always-on; Recipes = explicit invocation</td>
  <td>Skills = on-demand; AGENTS.md = always-on</td>
  <td>Skills = on-demand; AGENTS.md = always-on</td>
</tr>
<tr>
  <td>Partner/enterprise skill integrations</td>
  <td><span class="yes">Atlassian, Figma, Canva, Stripe, Notion, Zapier</span></td>
  <td><span class="no">None announced</span></td>
  <td><span class="yes">GitHub MCP server, Azure, Microsoft 365</span></td>
  <td><span class="yes">Same as Copilot</span></td>
  <td><span class="yes">OpenAI Developer Docs MCP, Linear</span></td>
  <td><span class="no">None announced</span></td>
  <td><span class="no">Block internal only</span></td>
  <td><span class="no">None announced</span></td>
  <td><span class="no">None announced</span></td>
</tr>
<tr>
  <td>Security / prompt injection mitigations</td>
  <td><span class="part">General safe messaging; no skill-specific sandbox</span></td>
  <td><span class="part">Skills scoped to workspace/global; tool whitelist via allowed-tools</span></td>
  <td><span class="part">Standard Copilot safety; no skill-specific sandbox</span></td>
  <td><span class="part">Standard VSC safety</span></td>
  <td><span class="yes">✔</span><br><span class="note">Sandbox filesystem; restricted read-only on Linux; avoids ~/.ssh; structured network approval</span></td>
  <td><span class="yes">✔</span><br><span class="note">Hooks can enforce deny policies (PreToolUse), security tool integrations</span></td>
  <td><span class="part">Extension permission model; recipes separate from skills</span></td>
  <td><span class="part">Standard safety</span></td>
  <td><span class="part">Standard safety</span></td>
</tr>
<tr>
  <td>Subagents / orchestration</td>
  <td><span class="yes">✔</span> Claude Code subagents</td>
  <td><span class="no">Not documented</span></td>
  <td><span class="yes">✔</span> Custom agents + handoffs; coding agent as cloud subagent</td>
  <td><span class="part">Via Copilot agent mode</span></td>
  <td><span class="yes">✔</span> Background agents, app-server thread API</td>
  <td><span class="yes">✔</span> Subagents (v2.4)</td>
  <td><span class="yes">✔</span> MCP extension orchestration</td>
  <td><span class="yes">✔</span> Subagent parallelization (thread sharing)</td>
  <td><span class="part">Via CLI orchestration</span></td>
</tr>
</tbody>
</table>
</div>


<!-- Legend -->
<div class="legend">
  <div class="legend-item"><div class="legend-dot" style="background:#34d399"></div> <span class="yes">✔ Yes / Fully supported</span></div>
  <div class="legend-item"><div class="legend-dot" style="background:#f87171"></div> <span class="no">✖ No / Not supported</span></div>
  <div class="legend-item"><div class="legend-dot" style="background:#fbbf24"></div> <span class="part">◑ Partial / Limited</span></div>
  <div class="legend-item"><div class="legend-dot" style="background:#fb923c"></div> <span class="exp">⚠ Experimental</span></div>
  <div class="legend-item"><div class="legend-dot" style="background:#a78bfa"></div> <span class="ext">★ Agent-specific extension (non-portable)</span></div>
  <div style="margin-left:auto;color:var(--muted);font-size:11px;">Data sourced from official docs, changelogs, GitHub repos &amp; community analysis. March 2026.</div>
</div>

</div><!-- end .cmp -->]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="agents" /><category term="coding agents" /><category term="llm" /><category term="comparison" /><category term="ai-tooling" /><category term="skill.md" /><summary type="html"><![CDATA[A comprehensive technical comparison of SKILL.md implementations across 9 major coding agents — spec compliance, directory layout, activation mechanics, tooling, and portability.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Your Skill Is a Behavioral Contract. Are You Sure It Holds?</title><link href="https://thinkingtokens.ai/2026/03/your-skill-is-a-behavioral-contract/" rel="alternate" type="text/html" title="Your Skill Is a Behavioral Contract. Are You Sure It Holds?" /><published>2026-03-03T00:00:00+00:00</published><updated>2026-03-03T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/03/your-skill-is-a-behavioral-contract</id><content type="html" xml:base="https://thinkingtokens.ai/2026/03/your-skill-is-a-behavioral-contract/"><![CDATA[<p>Let me tell you about the most dangerous assumption in agentic software development today. It isn’t prompt injection. It isn’t hallucination. It’s quieter than both, and it’s already in your repository right now.</p>

<p>The assumption is this: <strong>that the quality of a Skill is determined by the care with which it was written.</strong></p>

<p>I’ve watched people spend hours crafting Skills for Claude Code — meticulously structured, lovingly worded, organized with clear headers. Then they ship them, watch the agent invoke them, and declare success. Two weeks later, they can’t explain why the Skill fires on 60% of the inputs it should handle, why it silently fails in Claude.ai but works fine in Claude Code, and why an agent running the Skill last Tuesday produced a subtly different result than the same agent running it today.</p>

<p>This is the Skills trap. And almost everyone falls into it.</p>

<p>The root cause isn’t bad writing. It’s a fundamental misunderstanding of what a Skill actually is.</p>

<hr />

<h2 id="a-skill-is-not-documentation-its-a-behavioral-contract">A Skill Is Not Documentation. It’s a Behavioral Contract.</h2>

<p>Here’s the first aha moment, and it reframes everything that follows: <strong>a Skill is a contract between you and a reasoning system that will be invoked thousands of times across inputs you’ve never seen, in environments you may not have tested, by users who phrase their needs in ways you couldn’t anticipate.</strong></p>

<p>That word — contract — matters enormously. A contract has two failure modes. It can be broken by the other party, or it can be drafted poorly enough that “following it” produces outcomes you never intended. In agentic systems, the second failure mode is far more common, and far more insidious, because the agent will follow your instructions faithfully while producing exactly the wrong result.</p>

<p>This means your mindset when writing a Skill needs to shift from “how do I describe what this does?” to “what behavioral guarantees am I encoding, and how do I verify they hold?”</p>

<p>Everything in this guide flows from that shift.</p>

<hr />

<h2 id="the-architecture-youre-writing-into-most-people-skip-this">The Architecture You’re Writing Into (Most People Skip This)</h2>

<p>Before touching a single line of <code class="language-plaintext highlighter-rouge">SKILL.md</code>, you need to understand the three-tier loading system you’re working within, because it shapes every structural decision you’ll make.</p>

<p><strong>Tier 1 is your YAML frontmatter</strong> — the <code class="language-plaintext highlighter-rouge">name</code> and <code class="language-plaintext highlighter-rouge">description</code> fields. This is always in the agent’s context window, even when the Skill is not being used. It’s approximately 100 words, and it acts as the <em>sole decision gate</em>: the agent reads it and decides whether to consult your Skill at all. This is the most consequential real estate in your entire codebase.</p>

<p><strong>Tier 2 is your <code class="language-plaintext highlighter-rouge">SKILL.md</code> body</strong> — the actual instructions. This only loads when the Skill has been triggered. Here’s what most developers miss: it competes directly with the rest of the context window — user messages, file contents, tool outputs, conversation history. A bloated Skill body doesn’t just waste space. It crowds out the very information the agent needs to <em>apply</em> your Skill correctly. Keep this under 500 lines as a strong default.</p>

<p><strong>Tier 3 is your bundled resources</strong> — scripts, references, assets. These load only on demand. Scripts can even be <em>executed</em> without being read into context at all, meaning you can have a 2,000-line Python library powering your Skill without consuming a single token of context unless absolutely necessary.</p>

<p>The practical discipline this creates: <strong>don’t put Tier 3 content in Tier 2.</strong> If you have AWS-specific deployment instructions, they don’t belong in <code class="language-plaintext highlighter-rouge">SKILL.md</code>. They belong in <code class="language-plaintext highlighter-rouge">references/aws.md</code>, with a pointer that says “if deploying to AWS, read <code class="language-plaintext highlighter-rouge">references/aws.md</code> before proceeding.” This pattern — progressive disclosure — is one of the highest-leverage structural choices you can make, and most developers never make it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>skill-name/
├── SKILL.md                    ← Frontmatter + core instructions only
└── bundled-resources/
    ├── scripts/                ← Deterministic, executable operations
    ├── references/             ← Domain docs, loaded only when needed
    └── assets/                 ← Templates and output artifacts
</code></pre></div></div>

<p>For Skills spanning multiple cloud providers or platforms, decompose references by variant so the agent reads <em>only the relevant file</em> for each invocation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cloud-deploy/
├── SKILL.md                    ← Workflow + provider selection logic
└── references/
    ├── aws.md
    ├── gcp.md
    └── azure.md
</code></pre></div></div>

<p>This keeps every invocation lean. An agent deploying to GCP never loads the AWS reference. It sounds obvious written this way, but the monolithic alternative is the default pattern you’ll find in the wild.</p>

<hr />

<h2 id="the-triggering-problem-your-most-important-line-of-code">The Triggering Problem: Your Most Important Line of Code</h2>

<p>Here’s the second aha moment, and it stings a little: <strong>the <code class="language-plaintext highlighter-rouge">description</code> field in your YAML frontmatter is not metadata. It is your entire triggering mechanism. And you are almost certainly writing it wrong.</strong></p>

<p>The agent sees every available Skill’s name and description simultaneously, then decides whether yours is relevant to the current task. If your description is vague, passive, or misses trigger context, your Skill won’t fire — even on inputs it was built to handle perfectly.</p>

<p>There’s a documented <strong>undertriggering bias</strong> at play here. If an agent believes it can handle something directly, it will — even when consulting your Skill would produce substantially better results. The agent is not lazy; it’s confident. And your description needs to counteract that confidence by being explicit about situations where your Skill adds value that direct handling won’t.</p>

<p>This means descriptions need to be slightly more “pushy” than feels natural. Instead of describing what the Skill <em>can</em> do, describe the situations in which consulting it adds irreplaceable value.</p>

<p>Compare these two descriptions for a commit message Skill:</p>

<blockquote>
  <p><strong>Weak:</strong> <em>“Creates commit messages in conventional format.”</em></p>
</blockquote>

<blockquote>
  <p><strong>Strong:</strong> <em>“Creates structured commit messages following the Conventional Commits specification. Use this whenever the user is making a git commit, asking for a commit message, wants to summarize changes, or mentions staging, committing, or pushing — even if they just say ‘help me commit this’. Handles multi-file changes, breaking changes, scopes, and footers. Use even for simple single-file changes — consistency matters more than simplicity here.”</em></p>
</blockquote>

<p>The second version converts edge cases into explicit trigger conditions. That phrase “even if they just say ‘help me commit this’” is doing real work — it’s directly counteracting the undertriggering bias by preemptively telling the agent not to handle that case on its own.</p>

<p>Your description should contain four distinct elements working together: what the Skill does (capability), when to use it phrased as <em>user behaviors</em> rather than abstract task types, where <em>not</em> to use it to prevent false triggers in adjacent domains, and any environment assumptions the Skill makes. A Skill that assumes a monorepo layout or a Python backend should say so — so it doesn’t trigger inappropriately in a Go microservices project.</p>

<hr />

<h2 id="the-environment-trap-that-breaks-everything-silently">The Environment Trap That Breaks Everything Silently</h2>

<p>This is the gap I see most consistently in production Skills, and it causes a specific and maddening failure pattern: the Skill works perfectly in your testing environment, then silently fails in production for a subset of users, with no error, no signal, and no obvious debugging path.</p>

<p>The problem is <strong>environment blindness</strong>. The same <code class="language-plaintext highlighter-rouge">SKILL.md</code> may be invoked across fundamentally different execution contexts.</p>

<p>In <strong>Claude Code</strong>, you have a full terminal, subagents for parallel execution, a persistent filesystem, and browser access. You can run parallel test cases, use CLI tools like <code class="language-plaintext highlighter-rouge">claude -p</code>, and open local review servers. This is the richest environment.</p>

<p>In <strong>Claude.ai</strong>, there are no subagents. Test cases must run sequentially. You can’t do meaningful baseline comparisons. Any script that tries to open an HTML viewer will silently fail, consume compute, and give no signal about what went wrong.</p>

<p>In <strong>Cowork</strong>, subagents are available and parallel execution works well. Depending on the task context and configuration, browser or display access may not be available in certain workflows — in those cases, tools that open HTML viewers need a <code class="language-plaintext highlighter-rouge">--static</code> flag to write a standalone file instead, and feedback delivery differs: rather than a “Submit Reviews” button posting to a local server, it downloads a <code class="language-plaintext highlighter-rouge">feedback.json</code> file to be read from the filesystem. The point isn’t a definitive capability list for Cowork as a product — it’s that the same workflow may require different paths depending on what the environment exposes at runtime.</p>

<table>
  <thead>
    <tr>
      <th>Capability</th>
      <th>Claude Code</th>
      <th>Claude.ai</th>
      <th>Cowork</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Subagents</td>
      <td>✅</td>
      <td>✗</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>Browser / display</td>
      <td>✅</td>
      <td>✗</td>
      <td>varies by context</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">claude -p</code> CLI</td>
      <td>✅</td>
      <td>✗</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>Parallel test runs</td>
      <td>✅</td>
      <td>✗</td>
      <td>✅</td>
    </tr>
    <tr>
      <td>Filesystem persistence</td>
      <td>✅</td>
      <td>limited</td>
      <td>✅</td>
    </tr>
  </tbody>
</table>

<p>The solution is conditional branching in your Skill body. Not a separate Skill per environment — that creates maintenance overhead — but explicit conditional blocks:</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gu">## Running the review viewer</span>

If you're in Claude Code:
  Run <span class="sb">`generate_review.py`</span> and open the local server URL in the browser.

If you're in Claude.ai:
  Skip the browser viewer entirely. Present results directly in conversation,
  walk through each test case output, and ask for inline feedback.

If browser access is unavailable (e.g. certain Cowork configurations):
  Use <span class="sb">`generate_review.py --static /tmp/review.html`</span> and give the user
  a file path they can open in their own browser.
</code></pre></div></div>

<p>A Skill that silently fails in Claude.ai is worse than a Skill that doesn’t exist. The former consumes compute and produces no output; the latter at least makes the gap obvious.</p>

<hr />

<h2 id="the-writing-practice-that-separates-good-skills-from-great-ones">The Writing Practice That Separates Good Skills from Great Ones</h2>

<p>Here’s the third aha moment, and it’s the one that has the most immediate practical effect: <strong>stop writing rules. Start writing reasoning.</strong></p>

<p>When you write <code class="language-plaintext highlighter-rouge">ALWAYS use this exact template</code> or <code class="language-plaintext highlighter-rouge">NEVER skip this step</code>, you’re treating a sophisticated reasoning system like a state machine. But modern coding agents have deep reasoning capabilities — they generalize, adapt to edge cases, and make judgment calls. When you give them the <em>why</em> behind a rule, they apply it better across novel inputs than they ever would from the rule alone.</p>

<p>Compare these two instructions for a timing data capture step:</p>

<blockquote>
  <p><strong>Rigid:</strong> <em>“ALWAYS save timing data immediately when each subagent task completes.”</em></p>
</blockquote>

<blockquote>
  <p><strong>Explanatory:</strong> <em>“Save timing data as soon as each subagent task completes — this data arrives through the task notification and isn’t persisted anywhere else in the system. If you don’t capture it at the moment the notification arrives, it’s gone permanently. There’s no way to reconstruct it from logs or state.”</em></p>
</blockquote>

<p>The second version encodes the urgency and the mechanism. The agent now understands this isn’t an arbitrary rule — it’s about a data loss race condition with no recovery path. That understanding carries into edge cases the instruction never anticipated: what happens when two tasks complete almost simultaneously, what to do if the notification arrives during another operation, how to prioritize when system resources are constrained.</p>

<p>Heavy use of <code class="language-plaintext highlighter-rouge">MUST</code>, <code class="language-plaintext highlighter-rouge">NEVER</code>, and <code class="language-plaintext highlighter-rouge">ALWAYS</code> in all caps is a yellow flag in your own writing. Every time you reach for one, pause and ask: <em>what is the underlying reason this matters?</em> Write that instead. The result is more generalizable, more humane, and — empirically — more effective.</p>

<hr />

<h2 id="design-for-three-modes-not-one-linear-script">Design for Three Modes, Not One Linear Script</h2>

<p>Coding agents switch between reasoning and action in ways that most Skills don’t account for. Every production-grade Skill should explicitly address three modes of operation — not as three labeled sections, but as three <em>concerns</em> that your instructions cover somewhere.</p>

<p><strong>Plan mode</strong> is about decomposition and preflight verification before anything irreversible happens. What preconditions must be true? Is the agent on the right branch? Are there uncommitted changes that could be clobbered? Are required tools installed at the right version? These checks prevent the entire class of failures where an agent confidently executes the right steps in the wrong context — which is one of the most expensive failure modes in coding agent workflows.</p>

<p><strong>Execute mode</strong> is the command and file edit sequence. Instructions here should be short, exact, and specify the expected side effect of each step. Prefer minimal diffs and localized edits over broad rewrites. Define ordering constraints when multiple files must change atomically. Explicitly mark “do not touch” zones: generated files, vendored code, lock files. These aren’t nice-to-haves — they’re the difference between a Skill that’s safe to run autonomously and one that occasionally corrupts state in ways that take hours to debug.</p>

<p><strong>Validate mode</strong> is where your Skill proves its own correctness. A Skill is incomplete unless it specifies how to verify that the work is done. A good validation stack moves from fast to slow: format/lint/typecheck first, then targeted tests on changed modules, then integration or smoke tests on critical paths, then artifact verification. Crucially, define explicit “done” gates — minimum acceptance criteria the agent uses to decide when to stop iterating rather than running tests indefinitely or declaring success prematurely.</p>

<hr />

<h2 id="script-first-for-anything-deterministic">Script-First for Anything Deterministic</h2>

<p>Any shell snippet or operation that appears repeatedly across different test case runs should become a script in <code class="language-plaintext highlighter-rouge">scripts/</code>. This is one of the most reliable ways to improve Skill consistency, and it’s almost universally underused.</p>

<p>Here’s why it matters: when agents regenerate shell commands from scratch each invocation, they introduce variation — slightly different flags, different error handling, different output formats. That variation accumulates across runs and creates debugging nightmares where “the same Skill” produces subtly different results depending on when you run it.</p>

<p>A practical diagnostic: after running three or more test cases, read the transcripts and look for repeated patterns. If two out of three agents independently wrote nearly identical helper code — a script to aggregate benchmark results, a script to build a Word document, a script to open a review viewer — that code belongs in <code class="language-plaintext highlighter-rouge">scripts/</code>. The Skill then simply says “run <code class="language-plaintext highlighter-rouge">scripts/aggregate_benchmark.py</code> with the workspace path as an argument,” and the agent executes it without regenerating or re-reasoning about the implementation. The same proven code runs every time. You can test it independently. You can version it.</p>

<p>Scripts should be parameterized (avoid hardcoded repo-specific paths unless truly required), idempotent where possible (safe to run twice without corrupting state), and accompanied by usage examples and expected output in comments. This last point matters more than it looks: an agent reading a script it didn’t write needs to understand what “success” looks like to know whether to continue or escalate.</p>

<hr />

<h2 id="the-eval-loop-is-not-optional-its-the-entire-job">The Eval Loop Is Not Optional. It’s the Entire Job.</h2>

<p>Here’s the fourth and most important aha moment, the one that fundamentally distinguishes engineers who ship reliable Skills from those who ship Skills that almost work: <strong>Skill quality is an empirical question, not a design question. You cannot reason your way to a great Skill. You have to measure it.</strong></p>

<p>The development loop looks like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Draft Skill → Write realistic test cases → Run with-skill AND baseline →
Read transcripts + outputs → Draft assertions → Grade results →
Improve Skill → Repeat
</code></pre></div></div>

<p>Every step in this loop matters, and the order matters. Let me walk through the parts that most developers skip.</p>

<p><strong>Always run a baseline.</strong> For every test case, run two versions simultaneously: one using your Skill and one without (or, for Skill improvements, one using the previous version). Running only the with-skill case makes every iteration feel like progress because you have no reference point. It is the measurement equivalent of testing software without knowing what it’s supposed to do.</p>

<p><strong>Read the transcripts, not just the outputs.</strong> This is the single most underemphasized practice in Skill development. The final output of a Skill invocation is what the agent produced. The transcript is <em>how it got there</em> — every tool call, every intermediate step, every backtrack and retry. These are completely different sources of information, and you need both.</p>

<p>Transcripts reveal things that outputs hide. If an agent ran the same verification command three times before accepting the result, your success criteria are ambiguous. If every test case agent independently wrote the same 40-line helper script, that script belongs in <code class="language-plaintext highlighter-rouge">scripts/</code>. If agents are setting up scaffolding and then tearing it down, some instruction is creating unnecessary work. If an agent hesitated before a destructive operation but proceeded anyway, your preflight checks are insufficiently explicit. None of this is visible in the final output.</p>

<p><strong>Write realistic test cases.</strong> Real prompts are lowercase, contain typos, use abbreviations, include irrelevant context, and describe the goal rather than the method. “My boss just sent me this file and she wants a margin column added” is a real prompt. “Create a spreadsheet with a calculated profit margin column” is a textbook prompt. Test with the former.</p>

<hr />

<h2 id="the-overfitting-trap-fixing-the-test-instead-of-the-category">The Overfitting Trap: Fixing the Test Instead of the Category</h2>

<p>When you receive feedback from test case review, your instinct will be to make a specific fix for the specific failing case. This instinct is almost always wrong.</p>

<p>Remember: your Skill will be invoked across thousands of inputs you’ve never seen. Fixing it narrowly for your test case without understanding the general class of failure is a form of overfitting that shows up as brittleness in production — the Skill handles your test cases perfectly and fails mysteriously on everything else.</p>

<p>Before touching the Skill, ask: <em>what category of input does this failure represent?</em> Not “the agent missed the margin column” but “the agent failed to infer output column placement from positional context in the user’s description.” Then write the improvement to address that category, not the instance.</p>

<p>If you find yourself writing a very specific instruction like <em>“if the user mentions column C as revenue and column D as costs, put the margin column in column E”</em> — stop. That’s a dead giveaway you’re overfitting. The better instruction explains the reasoning: <em>“Infer output placement from the user’s column references and natural reading order of the data, placing calculated columns adjacent to the inputs they’re derived from.”</em> The second version handles every variant of this failure mode, including ones you haven’t seen yet.</p>

<hr />

<h2 id="description-optimization-the-last-step-not-the-first">Description Optimization: The Last Step, Not the First</h2>

<p>Almost everyone gets this backwards: they obsess over whether the Skill triggers correctly before verifying that it produces good outputs when it does trigger. If your Skill produces mediocre outputs, getting it to trigger more reliably just means more mediocre outputs.</p>

<p>Description optimization is a <strong>distinct, late-stage activity</strong> that happens after you’ve confirmed the Skill produces excellent results. The process is empirical: generate approximately 20 trigger eval queries — a balanced mix of should-trigger and should-not-trigger cases — and run each one multiple times, because variance matters enormously. A trigger that fires one out of three times is a fundamentally different problem than one that fires three out of three.</p>

<p>The most valuable test cases are the near-misses: queries that share keywords with your Skill but actually need something different. “Write a fibonacci function” as a negative test for a PDF Skill is too easy. You want genuinely adversarial cases where a naive keyword match would trigger but shouldn’t. Real queries look like real user messages:</p>

<blockquote>
  <p><strong>Should trigger:</strong> <em>“ok so my boss just sent me this xlsx file (its in my downloads, called something like ‘Q4 sales final FINAL v2.xlsx’) and she wants me to add a column that shows the profit margin as a percentage. Revenue is col C, costs D i think”</em></p>
</blockquote>

<blockquote>
  <p><strong>Should not trigger:</strong> <em>“can you help me write a python script that reads a csv and generates some charts for a presentation”</em></p>
</blockquote>

<p>Evaluate against a held-out test set rather than just the training queries. You can easily overfit a description to the examples you’re thinking about while writing it, and that description will fail on phrasing you didn’t anticipate. The held-out set is your protection against that.</p>

<hr />

<h2 id="the-anti-patterns-that-are-silently-killing-your-skills">The Anti-Patterns That Are Silently Killing Your Skills</h2>

<p>Let me be direct about the failure modes I see most often, because they’re all fixable once you can name them.</p>

<p><strong>Overly broad scope</strong> is the most common. A Skill that “handles everything related to Python projects” is a Skill that handles nothing reliably. Narrow scope with precise triggers almost always outperforms broad scope with vague ones — because the agent can reason clearly about when to use it.</p>

<p><strong>Passive description language</strong> causes chronic undertriggering. Descriptions that describe what a Skill <em>can</em> do rather than what it <em>should</em> trigger on will miss a significant fraction of legitimate invocations. Rewrite descriptions in terms of user behaviors and situations, not abstract capabilities.</p>

<p><strong>Ignoring transcripts</strong> is the debugging equivalent of reading compiled binaries instead of source code. The transcript is the source of truth for what the agent actually did. If you’re not reading them, you’re flying blind.</p>

<p><strong>Untested scripts</strong> in <code class="language-plaintext highlighter-rouge">scripts/</code> will fail in production in ways that are hard to diagnose, because the agent will execute them with confidence. Every script should be tested against realistic fixtures before shipping — not “looks right,” but actually run.</p>

<p><strong>Massive reference dumps</strong> consistently produce worse results than well-organized focused files. A 1,500-line monolithic reference with no table of contents forces the agent to scan the whole thing on every invocation. Decompose by domain, add a table of contents for any file over 300 lines, and make the Skill point explicitly to the right file based on context.</p>

<p><strong>Hidden environment assumptions</strong> are the silent failures I described earlier. Skills that silently assume a specific OS, specific tool versions, or specific network access will fail in a fraction of invocations with no clear signal about why. Make assumptions explicit in your frontmatter and add preflight checks that verify them.</p>

<hr />

<h2 id="the-definition-of-done">The Definition of Done</h2>

<p>A Skill is production-ready when all six of these properties hold simultaneously — not five out of six, but all six. A change that improves output quality but breaks triggering reliability is a net regression. A change that improves triggering but introduces a new failure mode in execution has the same problem.</p>

<p>The six properties: triggering is precise and reliable (verified empirically, not assumed); instructions are concise and mode-aware (covering plan, execute, and validate without being a rigid flowchart); repetitive logic is script-backed and the scripts are tested; validation gates are explicit and achievable (the agent can determine “done” without human confirmation); failure paths and reporting standards are defined for the most likely failure modes; and an iteration process exists with measurable feedback so the Skill can evolve.</p>

<p>That last point — the iteration process — is the one that distinguishes a Skill as a software artifact from a Skill as a document you wrote once and hoped for the best. The best Skills I’ve seen are treated like production services: they have owners, they have runbooks, they have metrics, and they get updated when the world changes around them.</p>

<hr />

<h2 id="the-core-insight">The Core Insight</h2>

<p>There is a version of Skill development where you write careful instructions and ship them, check that the output looks reasonable on a few examples, and declare the job done. Many teams are doing this right now.</p>

<p>There is another version where you treat a Skill as a behavioral contract, verify it against baselines, read the execution transcripts, run empirical trigger evals, and iterate on the failure categories rather than the individual instances. Very few teams are doing this.</p>

<p>The distance between those two approaches is the distance between Skills that almost work and Skills that work. The infrastructure for the second approach exists. The methodology is documented. The barrier is recognizing that the work doesn’t end when the writing ends — it ends when the measurement confirms it.</p>

<blockquote>
  <p><em>A Skill is not a document. It’s a behavioral contract. And like all contracts, its quality is determined not by how carefully it was drafted, but by how thoroughly it was tested.</em></p>
</blockquote>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="vibe coding" /><category term="coding agents" /><category term="agentic systems" /><category term="skill engineering" /><category term="claude code" /><summary type="html"><![CDATA[Let me tell you about the most dangerous assumption in agentic software development today. It isn’t prompt injection. It isn’t hallucination. It’s quieter than both, and it’s already in your repository right now.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Every AI Model Breaks! Red Teaming Isn’t About Prevention — It’s About Knowing How You’ll Fail</title><link href="https://thinkingtokens.ai/2026/02/every-ai-model-breaks/" rel="alternate" type="text/html" title="Every AI Model Breaks! Red Teaming Isn’t About Prevention — It’s About Knowing How You’ll Fail" /><published>2026-02-22T00:00:00+00:00</published><updated>2026-02-22T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/02/every-ai-model-breaks</id><content type="html" xml:base="https://thinkingtokens.ai/2026/02/every-ai-model-breaks/"><![CDATA[<blockquote>
  <p>The industry needs to stop treating red teaming as a security gate and start treating it as a continuous practice of failure cartography.</p>
</blockquote>

<p>Last year, <a href="https://www.grayswan.ai/news/uk-aisi-x-gray-swan-agent-red-teaming-challenge-results-snapshot">the UK AI Safety Institute &amp; Gray Swan</a> published something the industry had quietly been dreading: 1.8 million adversarial attacks across 22 frontier AI models, every result documented. Every single model was breached. Not most. Not the weaker ones. All of them.</p>

<p>A year on, the number still doesn’t surprise the researchers.
It still surprises the <strong>executives</strong> only.</p>

<p>That gap between what practitioners know and what organizations believe — is the central crisis in AI security today. And it’s a crisis being sustained, in large part, by a dangerous misreading of what red teaming is actually for.</p>

<h2 id="the-gate-metaphor-is-killing-us">The Gate Metaphor Is Killing Us</h2>

<p>Somewhere along the way, the industry adopted a metaphor for red teaming that fundamentally distorted the practice. Red teaming became a <strong>gate</strong> — something you pass through before launch, a box you check to earn the “responsibly deployed” label. Fail the red team exercise, fix the issues, run it again, pass, ship.</p>

<p>A big reason the gate metaphor persists is that we want LLMs to behave like traditional software components; deterministic, spec-following, and enforceable with the right controls. But the dominant failure mode in real deployments isn’t “the model forgot a rule.” It’s that the model is often placed in the role of a decision-making intermediary between untrusted inputs and privileged actions. However, they are probabilistic, high-dimensional systems that interact with an unbounded input space. The gate metaphor collapses under that reality.</p>

<p>This framing is intuitive. It mirrors how we think about penetration testing in traditional software security, code reviews before merge, or clinical trials before drug approval. It gives executives a clean story: we tested it, it’s safe, ship it.</p>

<h2 id="the-uncomfortable-truth-secure-is-the-wrong-binary">The uncomfortable truth: “secure” is the wrong binary</h2>

<p>Red teaming as a “ship/no-ship” gate assumes there is a stable end-state: you fix what you find, and you’re done.</p>

<p>But LLM systems don’t sit still:</p>

<ul>
  <li>Models change (provider updates, fine-tunes, system prompt edits).</li>
  <li>Tools change (new integrations, permissions, APIs, data sources).</li>
  <li>Attackers change (new prompt patterns, indirect injection tricks, multi-step social engineering).</li>
  <li>Use changes (new workflows that turn “harmless text” into “privileged action”).</li>
</ul>

<p>Even the UK AISI’s broader testing posture reflects this: it reports that safeguards are improving, but also that they’ve found vulnerabilities in every system tested, with large differences in the effort needed to jailbreak different models. That’s not a one-time certification story; it’s a moving distribution.</p>

<p>So instead of asking, “Did we pass red teaming?” the operationally honest question is:</p>

<blockquote>
  <p><strong>What do our failures look like today and what’s our plan when they happen?</strong></p>
</blockquote>

<p>That’s “continuous risk characterization.”</p>

<h2 id="what-knowing-how-youll-fail-looks-like-in-practice">What “knowing how you’ll fail” looks like in practice</h2>

<p>If you treat red teaming as risk characterization, you stop chasing the illusion of “no breaks” and start building a <em>map</em> of failure modes with metrics you can manage.</p>

<p>Here’s a practical way to think about it.</p>

<h3 id="1-a-failure-taxonomy-specific-to-your-system">1) A failure taxonomy specific to your system”</h3>

<p>Generic red team templates are a starting point, not an endpoint. The organization needs to develop and maintain a living document of known failure modes, ranked by exploitability and consequence. This is your threat model. It should be updated after every red team cycle, every significant model update, and every major deployment context change.
So, track it <strong>per release</strong>, <strong>per model config</strong>, <strong>per toolchain</strong>, <strong>per policy set</strong>.</p>

<p>This turns red teaming from theater into an engineering KPI.</p>

<h3 id="2-measure-blast-radius-not-just-attack-success">2) Measure <em>blast radius</em>, not just “attack success”</h3>

<p>A jailbreak that produces an off-policy paragraph is bad. A jailbreak that causes:</p>

<ul>
  <li>unauthorized data access,</li>
  <li>irreversible financial actions,</li>
  <li>exfiltration via tool calls,</li>
  <li>or policy-bypassing workflow execution</li>
</ul>

<p>…is categorically different.</p>

<p>The competition analysis describes policy violations that include unauthorized data access and illicit financial actions among the behaviors targeted in realistic deployments.</p>

<p>So score outcomes on <strong>impact tiers</strong>, and align mitigations to the highest tier, not the easiest-to-detect.</p>

<h3 id="3-measure-transferability-because-attackers-reuse">3) Measure <em>transferability</em>, because attackers reuse</h3>

<p>The paper highlights strong generalization/transferability of attacks across diverse agents and policies. If an exploit pattern transfers, it’s not “a bug”; it’s a <em>class</em>.</p>

<p>That has two implications:</p>

<ul>
  <li>You need a <strong>library of adversarial patterns</strong> that you continuously replay.</li>
  <li>You should expect “patch one scenario” fixes to leak elsewhere unless you address root causes (permissions, tool isolation, workflow design).</li>
</ul>

<h3 id="4-treat-the-model-as-untrusted-in-privileged-pathways">4) Treat the model as <em>untrusted</em> in privileged pathways</h3>

<p>This is the hardest cultural shift for teams that grew up on traditional appsec, but it’s the one that matters most.</p>

<p>Put differently: don’t ask the model to be your security boundary.</p>

<p>Microsoft’s guidance on AI red teaming stresses probing <strong>end-to-end systems</strong>, because risks emerge from interactions among models, user inputs, and external systems—not just the base model. That’s a polite way of saying: the moment your agent can click buttons, move money, or query internal systems, you must design like the agent will eventually be compromised.</p>

<h2 id="the-accountability-gap">The Accountability Gap</h2>

<p>The gate model persists because it produces a document, and our accountability systems reward documents. A red team report fits in a board deck, satisfies a regulator, and holds up in litigation. Continuous risk characterization doesn’t compress that cleanly, so it loses.</p>

<p>The failure runs through every layer. Regulators inherited auditing frameworks built for deterministic software; most binding AI governance, including the EU AI Act, still skews toward pre-market evaluation and leaves “assessed at launch” versus “monitored in production” largely unaddressed. Procurement teams accept red team reports without asking who owns adversarial testing post-deployment.</p>

<p>Boards treat AI risk as a reputational matter and ask the wrong question, “have we been red teamed?”, instead of the right one: “what’s our worst failure class, and how fast would we detect it in production?”
Answering that requires infrastructure. Building it is the actual work.</p>

<p>This will change when a high-profile incident is traced not to missing pre-deployment testing, but to the absence of monitoring that would have caught a known failure before it caused harm. The industry shouldn’t wait for that moment to define the standard.</p>

<h2 id="the-harder-conversation">The Harder Conversation</h2>

<p>There is a version of this argument that makes people uncomfortable, so let’s state it plainly.</p>

<p>The 100% breach rate finding does not mean AI models should not be deployed. It means they should be deployed with accurate risk intelligence, appropriate safeguards, and ongoing monitoring, not with the comfortable fiction that red teaming has rendered them safe.</p>

<p>The maturation of AI security will look less like “we found and fixed all the vulnerabilities” and more like “we understand our risk surface well enough to make informed deployment decisions and detect anomalies when they occur.” This is how we think about security in every other high-stakes domain — aviation, nuclear power, financial systems. We do not expect zero incidents. We build systems that fail gracefully, detect failures quickly, and learn from them rigorously.</p>

<p>Red teaming, in this framing, is not the last line of defense before deployment. It is the discipline of knowing your system well enough to deploy it honestly, and to keep knowing it as it changes.</p>

<p>Every model breaks. The organizations that understand this earliest will be the ones best positioned to deploy AI systems that are genuinely trustworthy, not just certified.</p>]]></content><author><name>Nur Gucu</name></author><category term="thoughts" /><category term="ai" /><category term="red-teaming" /><category term="llm" /><category term="adversarial" /><summary type="html"><![CDATA[The industry needs to stop treating red teaming as a security gate and start treating it as a continuous practice of failure cartography.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The Ouroboros Effect: Anatomy of Multi-Agent Exploits in the Wild</title><link href="https://thinkingtokens.ai/2026/02/the-ouroboros-effect-anatomy-of-multi-agent-exploits-in-the-wild/" rel="alternate" type="text/html" title="The Ouroboros Effect: Anatomy of Multi-Agent Exploits in the Wild" /><published>2026-02-18T00:00:00+00:00</published><updated>2026-02-18T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/02/the-ouroboros-effect-anatomy-of-multi-agent-exploits-in-the-wild</id><content type="html" xml:base="https://thinkingtokens.ai/2026/02/the-ouroboros-effect-anatomy-of-multi-agent-exploits-in-the-wild/"><![CDATA[<p>The next major class of AI security incidents won’t come from a single prompt
injection.  They’ll come from <em>interaction topology</em>.</p>

<p>As AI systems shift from standalone chat interfaces to multi-agent ecosystems,
we’re entering a new threat landscape — one where vulnerabilities emerge not
from individual models, but from how agents delegate, recurse, and trust each
other.  If you’re building or securing agentic systems, this is the layer that
deserves your attention.</p>

<h2 id="from-model-security-to-interaction-security">From Model Security to Interaction Security</h2>

<p>Most current AI security conversations focus on prompt injection, data
exfiltration, jailbreaks, and tool misuse.  Those matter.  But they assume a
single-agent context.</p>

<p>Modern AI architectures increasingly look like this: a Planner Agent decomposes
tasks, a Research Agent gathers external data, a Tool Agent executes API calls,
a Memory Agent stores intermediate state, and a Supervisor Agent reviews
results.  Each has partial autonomy.  Each can call tools.  Each can influence
others.</p>

<p>The result is not just a bigger system — it’s a reasoning network.  And
reasoning networks create new attack surfaces.</p>

<h2 id="the-core-problem-transitive-trust-without-enforcement">The Core Problem: Transitive Trust Without Enforcement</h2>

<p>In multi-agent systems, trust is often implicit.  Agents treat upstream outputs
as legitimate instructions.  Context is reused across reasoning loops.
Delegation chains are dynamically generated.</p>

<p>This creates a structural risk.</p>

<blockquote>
  <p>If Agent A can influence Agent B, and Agent B can influence Agent C, then
Agent A may indirectly control Agent C — even if never intended.</p>
</blockquote>

<p>That’s transitive trust.  In AI ecosystems it’s rarely enforced with
cryptographic or policy boundaries.  It’s enforced with assumptions.</p>

<h2 id="exploit-pattern-1-cross-agent-prompt-amplification">Exploit Pattern 1: Cross-Agent Prompt Amplification</h2>

<p>We’ve all seen single-model prompt injection.  The multi-agent version is worse.</p>

<p>An attacker injects malicious instructions into a data source — a web page, a
document, an API response.  The Research Agent summarizes it.  The Planner
Agent reformulates it.  The Executor Agent interprets it as an actionable
instruction:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Untrusted Source]
        ↓
[Research Agent]
        ↓
[Planner Agent]
        ↓
[Executor Agent]
        ↓
[Privileged Tool]
</code></pre></div></div>

<p>Each step reframes the malicious content as legitimate reasoning.  By the time
the instruction reaches a privileged agent it no longer looks like injection —
it looks like workflow logic.</p>

<p>Traditional defenses filter user input.  But in multi-agent systems, the
malicious content arrives as internal context, a delegated task, a structured
plan, or a reflection artifact.  Security layers often don’t inspect
inter-agent reasoning.  That’s the gap.</p>

<h2 id="exploit-pattern-2-recursive-loop-reinforcement">Exploit Pattern 2: Recursive Loop Reinforcement</h2>

<p>Many agent frameworks use a standard loop:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Think → Act → Observe → Reflect
         ↑_________________|
</code></pre></div></div>

<p>This is powerful — it enables planning and self-correction.  It also creates a
feedback amplifier.</p>

<p>If an attacker seeds a subtle misinterpretation early in the loop, the agent
may act on flawed reasoning, observe outcomes, rationalize them during
reflection, increase confidence, and escalate actions.  Recursive systems can
self-reinforce compromise:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Seeded False Assumption
        ↓
Think (based on poison)
        ↓
Act
        ↓
Observe partial confirmation
        ↓
Reflect (confidence ↑)
        ↺
Escalated Action
</code></pre></div></div>

<p>Unlike traditional bugs, this isn’t deterministic failure.  It’s probabilistic
escalation.  That makes detection harder.</p>

<h2 id="exploit-pattern-3-delegated-privilege-escalation">Exploit Pattern 3: Delegated Privilege Escalation</h2>

<p>Consider a realistic enterprise scenario:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Input
    ↓
Chat Agent (Low Privilege)
    ↓
Planner Agent (Medium Privilege)
    ↓
Infra Agent (High Privilege)
    ↓
Root Tool Access
</code></pre></div></div>

<p>The Chat Agent gets compromised via prompt injection.  Instead of executing
malicious code directly — it can’t — it frames a task:</p>

<blockquote>
  <p>“To resolve this issue, we need to rotate credentials and verify system
integrity.”</p>
</blockquote>

<p>Planning Agent agrees.  Infrastructure Agent executes.  The attacker never
touched the high-privilege agent directly.</p>

<p>This is reasoning-based lateral movement.  In traditional security, privilege
escalation exploits code paths.  In multi-agent systems, it exploits delegation
logic.  The shortest path from low privilege to root is your attack surface
metric.</p>

<h2 id="exploit-pattern-4-shared-memory-poisoning">Exploit Pattern 4: Shared Memory Poisoning</h2>

<p>Many agent architectures use shared memory — vector databases, persistent
state, scratchpads, planning logs.  If memory is writable and reusable,
attackers can inject long-lived malicious cues, embed delayed instructions, and
influence future reasoning cycles.</p>

<p>The risk isn’t immediate execution.  It’s future reinterpretation.  Memory
becomes a <strong>latent attack surface</strong>.</p>

<h2 id="what-makes-this-class-of-risk-different">What Makes This Class of Risk Different</h2>

<p>These exploits are not syntax-level injections, broken authentication flaws, or
buffer overflows.  They are <strong>semantic exploits</strong>.  They manipulate intent
inference, planning logic, delegation structure, and confidence loops.  The
vulnerability lives in the reasoning graph, not the codebase.</p>

<h2 id="the-real-blast-radius-emergent-behavior">The Real Blast Radius: Emergent Behavior</h2>

<p>In a single-agent system, compromise is localized.  In a multi-agent network,
one compromised agent can affect many, recursive loops magnify effects,
delegation chains expand privilege reach, and memory spreads contamination.  The
blast radius grows with connectivity.</p>

<table>
  <thead>
    <tr>
      <th>Surface Type</th>
      <th>Description</th>
      <th>Unique to Multi-Agent?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Inter-Agent Messaging</td>
      <td>Natural language as execution medium</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Delegation Chains</td>
      <td>Task passing with privilege layering</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Shared Memory</td>
      <td>Persistent context reuse</td>
      <td>Amplified</td>
    </tr>
    <tr>
      <td>Recursive Loops</td>
      <td>Self-reinforcing reasoning</td>
      <td>Amplified</td>
    </tr>
    <tr>
      <td>Tool Selection Logic</td>
      <td>LLM-driven execution routing</td>
      <td>Yes</td>
    </tr>
  </tbody>
</table>

<h2 id="designing-defenses-for-interaction-level-security">Designing Defenses for Interaction-Level Security</h2>

<p>Security must evolve beyond input validation.  Four principles, applied at the
architecture level — not the prompt level.</p>

<table>
  <thead>
    <tr>
      <th>Principle</th>
      <th>What to enforce</th>
      <th>What it stops</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Zero-Trust Inter-Agent</strong></td>
      <td>Validate every agent output as untrusted. Schema-check before tool calls. Natural language never triggers privileged actions directly.</td>
      <td>Prompt amplification across agent hops</td>
    </tr>
    <tr>
      <td><strong>Capability-Constrained Delegation</strong></td>
      <td>Scope tool access per agent. Make delegation explicit and auditable — not just logical.</td>
      <td>Privilege escalation via reasoning chains</td>
    </tr>
    <tr>
      <td><strong>Loop Stability Monitoring</strong></td>
      <td>Track recursion depth, confidence spikes, and repeated high-risk decisions at runtime.</td>
      <td>Self-reinforcing compromise cycles</td>
    </tr>
    <tr>
      <td><strong>Trust Graph Modeling</strong></td>
      <td>Model your system as a privilege graph. Find the shortest path from low-privilege to root. Close it.</td>
      <td>Undetected lateral movement</td>
    </tr>
  </tbody>
</table>

<h2 id="the-niche-insight-most-teams-miss">The Niche Insight Most Teams Miss</h2>

<p>The fundamental vulnerability isn’t prompt injection.  It’s <strong>unbounded
reasoning propagation</strong>.</p>

<p>Multi-agent systems create a new category of security concern: reasoning supply
chain attacks.  Just as software supply chains can be compromised upstream,
reasoning chains can be poisoned early and amplified downstream.  The more
agents collaborate, the more surface area exists for semantic compromise.</p>

<p>This is not a patch-level issue.  It’s an architectural one.</p>

<h2 id="interaction-is-the-new-perimeter">Interaction Is the New Perimeter</h2>

<p>In traditional security the perimeter was the network.  In modern SaaS it
became identity.  In agentic AI, the perimeter is interaction.</p>

<p>If agents can recursively reason, delegate, and act, then security must monitor
the graph, constrain reasoning, and verify intent — not just input.</p>

<p>Because in multi-agent systems, the most dangerous exploit isn’t the one that
breaks the model.  It’s the one that convinces the ecosystem to break itself.</p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="red-teaming" /><category term="llm" /><category term="adversarial" /><category term="multi-agent" /><summary type="html"><![CDATA[The next major class of AI security incidents won’t come from a single prompt injection. They’ll come from interaction topology.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Vibe Coding Agents Are Not What They Seem</title><link href="https://thinkingtokens.ai/2026/02/vibe-coding-agents-are-not-what-they-seem/" rel="alternate" type="text/html" title="Vibe Coding Agents Are Not What They Seem" /><published>2026-02-04T00:00:00+00:00</published><updated>2026-02-04T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/02/vibe-coding-agents-are-not-what-they-seem</id><content type="html" xml:base="https://thinkingtokens.ai/2026/02/vibe-coding-agents-are-not-what-they-seem/"><![CDATA[<p>“Vibe coding” became a word almost overnight.  Someone said it, it stuck,
and suddenly every LLM-powered tool that touches a codebase got slapped with
the label.  It feels right on the surface — you describe what you want, the
agent figures it out, code appears.  Vibes.</p>

<p>But the label is doing more harm than good.  It flattens something
architecturally interesting into something that sounds disposable.</p>

<h2 id="they-are-plan-action-agents-first">They Are Plan-Action Agents First</h2>

<p>Strip away the marketing and the memes.  What a “vibe coding agent” actually
is, under the hood, is a <strong>plan-action loop</strong>.  It receives a goal, breaks it
into steps, executes those steps against tools (file reads, shell commands,
API calls), observes the output, and re-plans based on what it sees.</p>

<p>That is not a new pattern.  That is the core architecture of every serious
autonomous agent being built right now.  The planning layer, the tool
interface, the observation-feedback cycle — it is all there.  The fact that
the <em>domain</em> happens to be code does not make the <em>architecture</em> special to
code.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Goal
  │
  ▼
┌─────────┐     ┌──────────┐     ┌─────────────┐
│  Plan   │────►│  Action  │────►│  Observe    │
│  Step   │     │  (Tool)  │     │  (Output)   │
└─────────┘     └──────────┘     └──────┬──────┘
      ▲                                 │
      │         re-plan if needed       │
      └─────────────────────────────────┘
</code></pre></div></div>

<p>A well-architected vibe coding agent is doing exactly what a well-architected
research agent, a well-architected ops agent, or a well-architected testing
agent does.  The loop is the same.  The tools are different.</p>

<h2 id="the-label-misleads-people-into-thinking-too-small">The Label Misleads People Into Thinking Too Small</h2>

<p>Here is the problem.  When you call something a “vibe coding agent”, people
mentally put it in a box.  The box is labeled <em>coding</em>.  And once it is in
that box, nobody asks the question that actually matters:</p>

<blockquote>
  <p>If this agent can plan, act, and adapt across a codebase — what else can
it do that with the same architecture?</p>
</blockquote>

<p>The answer is a lot.  And most teams are leaving it on the table.</p>

<p>A plan-action agent that can navigate a codebase can navigate a test suite.
It can navigate a deployment pipeline.  It can navigate an incident
triage workflow.  It can navigate a compliance checklist.  The cognitive
structure is identical — the only thing that changes is the set of tools you
hand it and the system prompt that defines the domain.</p>

<p>Calling it a “vibe coding agent” means you stop at the first application
and never notice the pattern underneath.  That is a missed automation
opportunity, every single time.</p>

<h2 id="agent-steering--keeping-the-vibe-controlled">Agent Steering — Keeping the Vibe Controlled</h2>

<p>The flip side of a capable plan-action agent is that it needs steering.
Left unchecked, these agents will find a path to the goal — but it might not
be the path you wanted.</p>

<p>Agent steering is the practice of shaping that path without micromanaging
every step.  There are a few layers to it:</p>

<p><strong>Constraint-level steering</strong> — what the agent is <em>allowed</em> to do.  This is
tool gating.  If you do not give it a shell execution tool, it cannot run
arbitrary commands.  If you scope its file access to a single directory, it
stays there.  The architecture enforces the boundary; the agent never has to
reason about it.</p>

<p><strong>Goal-level steering</strong> — what the agent is <em>trying</em> to do.  This is the
system prompt and the task definition.  The difference between a useful
agent and a chaotic one is often just how precisely the goal is framed.
Not a sentence.  A structured decomposition.  What success looks like.
What is out of scope.</p>

<p><strong>Feedback-level steering</strong> — what the agent <em>learns</em> mid-run.  If the agent
hits an error and re-plans on its own, does it converge or does it spiral?
Good agents have guardrails on re-planning depth.  They surface uncertainty
instead of silently guessing.  This is where most vibe coding agents are
weakest, and it is the layer that separates a prototype from something you
can trust in production.</p>

<p>Steering is not prompt engineering.  It is an architectural decision made
before the agent runs.</p>

<h2 id="the-hard-problem-multiple-agents-one-project">The Hard Problem: Multiple Agents, One Project</h2>

<p>Now make it interesting.  You have not one vibe coding agent but several —
each one working on a different part of the same project.  One is writing
feature code.  Another is writing tests.  A third is handling a bugfix in
the same module.  All of them are plan-action loops.  All of them are
touching the same files.</p>

<p>This is where the “vibe” breaks down fast.</p>

<p><strong>Resource contention is not a vibe problem, it is a systems problem.</strong>  Two
agents writing to the same file at the same time will produce garbage.  Not
sometimes.  Consistently.  There is no built-in locking, no transaction
layer, no merge strategy.  The agents do not know about each other unless
you explicitly wire that in.</p>

<p><strong>Consistency is invisible until it is not.</strong>  Agent A refactors a function
signature.  Agent B, working in parallel, calls that function with the old
signature.  Neither agent is wrong in isolation.  Together they produce a
build that does not compile.  The failure is emergent — it only exists in
the gap between two otherwise-correct plans.</p>

<p><strong>Orchestration is the missing layer.</strong>  If you have multiple agents on one
project, you need something above them that coordinates.  A meta-agent, a
scheduler, a shared state store — something that understands the dependency
graph of the work and sequences or partitions the agents accordingly.  This
is not optional.  It is the difference between a multi-agent system and a
collection of agents that happen to be running at the same time.</p>

<p>The challenges stack:</p>

<ul>
  <li><strong>Partition the work</strong> so agents do not step on each other.  This requires
understanding the codebase structure before dispatching.</li>
  <li><strong>Sequence the dependencies.</strong>  Some tasks must finish before others start.
A feature agent cannot finish if the interface it depends on is still being
designed by another agent.</li>
  <li><strong>Merge and validate.</strong>  When agents hand off their work, something has to
check that the pieces fit together.  Ideally another agent.  Ideally one
that is good at exactly that.</li>
  <li><strong>Detect and recover from conflicts.</strong>  When contention does happen —
and it will — the system needs to notice, surface the conflict, and
re-plan.  Not silently overwrite.</li>
</ul>

<h2 id="what-this-actually-means">What This Actually Means</h2>

<p>Vibe coding agents are not magic.  They are plan-action agents with a
specific tool set and a very appealing user experience.  The experience is
real.  The architecture is not new.</p>

<p>If you are building with them, think past the code.  The same loop that
writes a component can automate a dozen other workflows.  But if you are
deploying multiple ones on the same project, you are not doing vibe coding
anymore.  You are doing agent orchestration.  And that is a harder, more
interesting problem.</p>

<p>One worth solving properly.</p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="agents" /><category term="llm" /><category term="automation" /><category term="orchestration" /><category term="ai-architecture" /><category term="red-teaming" /><summary type="html"><![CDATA[“Vibe coding” became a word almost overnight. Someone said it, it stuck, and suddenly every LLM-powered tool that touches a codebase got slapped with the label. It feels right on the surface — you describe what you want, the agent figures it out, code appears. Vibes.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Where I Drop AI Red Teaming Tips</title><link href="https://thinkingtokens.ai/2026/01/ai-red-teaming-tips-on-github/" rel="alternate" type="text/html" title="Where I Drop AI Red Teaming Tips" /><published>2026-01-30T00:00:00+00:00</published><updated>2026-01-30T00:00:00+00:00</updated><id>https://thinkingtokens.ai/2026/01/ai-red-teaming-tips-on-github</id><content type="html" xml:base="https://thinkingtokens.ai/2026/01/ai-red-teaming-tips-on-github/"><![CDATA[<p>Not everything I work on needs a full writeup.  Some findings are a single
technique, a single vector, a single “oh, that’s interesting” moment.  Those
live somewhere else — and that somewhere is
<a href="https://github.com/nuryslyrt/AISecTips-Tricks">AISecTips-Tricks</a>.</p>

<h2 id="what-it-is">What It Is</h2>

<p>A GitHub repo where I keep bite-sized AI security tips.  No fluff, no padding.
Each one is a focused markdown file: the attack surface, how it works, and
what hardening looks like.  Red team and blue team, both sides covered.</p>

<h2 id="whats-in-there-right-now">What’s In There Right Now</h2>

<p>Eight tips, all from the offensive research I’ve been running.  The topics
span most of the surfaces I care about:</p>

<ul>
  <li><strong>RAG Embedding Poisoning</strong> — corrupting vector stores so retrieval
silently serves attacker-controlled content.</li>
  <li><strong>Merkle-Chained Vector Chunks</strong> — tamper-proofing the other side of that
same problem.</li>
  <li><strong>LoRA Ghost-Adapter Sig-Scans</strong> — detecting supply-chain backdoors baked
into adapter weights.</li>
  <li><strong>Shadow Batch KV-Poisoning</strong> — manipulating attention by poisoning the KV
cache across batches.</li>
  <li><strong>Router-Sniff</strong> — cross-batch prompt leakage inside Mixture-of-Experts
routing.</li>
  <li><strong>Cache Whispering</strong> — hardware-level CPU cache side-channels during token
generation.</li>
  <li><strong>Draft-Leak</strong> — timing oracles hidden inside speculative decoding.</li>
  <li><strong>Ghost-Tool Shadowing</strong> — hijacking tools through MCP protocol
manipulation in agentic workflows.</li>
</ul>

<h2 id="why-keep-it-separate">Why Keep It Separate</h2>

<p>The blog here is for deeper dives — the kind of post where I walk through the
full chain of thought.  The repo is for the moments where the finding is sharp
enough to stand on its own.  Two formats, same research.</p>

<p>If something from the repo deserves the long treatment, it’ll show up here
eventually.</p>

<p>Go <a href="https://github.com/nuryslyrt/AISecTips-Tricks">star it</a> if the topics
interest you.  New tips drop when they drop.</p>]]></content><author><name>Nur Gucu</name></author><category term="technical" /><category term="ai" /><category term="red-teaming" /><category term="llm" /><category term="tips" /><category term="github" /><category term="rag" /><category term="mcp" /><summary type="html"><![CDATA[Not everything I work on needs a full writeup. Some findings are a single technique, a single vector, a single “oh, that’s interesting” moment. Those live somewhere else — and that somewhere is AISecTips-Tricks.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" /><media:content medium="image" url="https://thinkingtokens.ai/thinkingtokens_preview_logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>