<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:blog="https://jonesrussell.github.io/blog/ns"><channel><title>Codex on Web Developer Blog</title><link>https://jonesrussell.github.io/blog/tags/codex/</link><description>Recent content in Codex on Web Developer Blog</description><image><title>Web Developer Blog</title><url>https://jonesrussell.github.io/blog/images/og-default.png</url><link>https://jonesrussell.github.io/blog/images/og-default.png</link></image><generator>Hugo -- 0.166.0</generator><language>en-us</language><lastBuildDate>Sun, 20 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jonesrussell.github.io/blog/tags/codex/feed.xml" rel="self" type="application/rss+xml"/><item><title>Claude Code and Codex skills are directories, not files</title><link>https://jonesrussell.github.io/blog/claude-code-codex-skill-directories/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0000</pubDate><guid>https://jonesrussell.github.io/blog/claude-code-codex-skill-directories/</guid><category>ai</category><blog:tag>claude-code</blog:tag><blog:tag>codex</blog:tag><blog:tag>ai-agents</blog:tag><blog:tag>waaseyaa</blog:tag><description>Why Claude Code and Codex discover agent skills as a directory containing SKILL.md, not a flat markdown file, and what silently breaks when an installer gets that wrong.</description><content:encoded><![CDATA[<p>Ahnii!</p>
<p>If you&rsquo;re building tooling that installs &ldquo;skills&rdquo; for AI coding agents, it&rsquo;s tempting to treat a skill as just another markdown file you drop somewhere in the repo. It isn&rsquo;t. Both <a href="https://code.claude.com/docs/en/skills">Claude Code</a> and <a href="https://learn.chatgpt.com/docs/build-skills">OpenAI Codex</a> discover skills by walking the project tree for a <strong>directory</strong> that contains a <code>SKILL.md</code> file, not a flat file. Here&rsquo;s what each client actually looks for, the bug a shape mismatch causes, and how <a href="https://waaseyaa.org/">Waaseyaa</a>&rsquo;s installer package, Bimaaji, fixed it by sharing one renderer across both clients instead of maintaining two.</p>
<h2 id="what-claude-code-actually-discovers">What Claude Code actually discovers</h2>
<p>A Claude Code project skill lives at:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>.claude/skills/&lt;skill-name&gt;/SKILL.md
</span></span></code></pre></div><p>Two details matter here:</p>
<ul>
<li><strong>The command name comes from the directory name</strong>, not from the <code>name</code> field in the file&rsquo;s frontmatter. The frontmatter <code>name</code> is only the display label shown in skill listings.</li>
<li><strong>Frontmatter is only recognized when the opening <code>---</code> is the file&rsquo;s first line.</strong> If anything precedes it — a comment, a blank line, a provenance marker — Claude Code won&rsquo;t parse it as frontmatter at all.</li>
</ul>
<p>A flat <code>.claude/skills/&lt;name&gt;.md</code> file is not a documented layout, and Claude Code doesn&rsquo;t discover it. Bimaaji&rsquo;s installer originally emitted exactly that flat shape, and every &ldquo;file written&rdquo; count it reported was quietly counting output the client would never load.</p>
<h2 id="what-codex-actually-discovers">What Codex actually discovers</h2>
<p>Codex&rsquo;s convention is split in two:</p>
<ul>
<li>A root <code>AGENTS.md</code> for always-loaded project guidance — the same vendor-neutral file <a href="https://agents.md">Devin Desktop and JetBrains Junie</a> read.</li>
<li>Detailed, on-demand skills under <code>.agents/skills/&lt;skill-name&gt;/SKILL.md</code>, discovered by walking from the current working directory up to the repository root.</li>
</ul>
<p>Codex&rsquo;s per-skill directory shape is the same structural contract as Claude Code&rsquo;s: a directory per skill, a <code>SKILL.md</code> inside it, <code>name</code>/<code>description</code> metadata in frontmatter. Bimaaji&rsquo;s installer used to fold every skill body straight into <code>AGENTS.md</code> as one consolidated file. That worked, in the sense that Codex could read it, but it threw away the on-demand loading both clients are designed around — the whole point of a skill is that its detail loads only when needed, not on every request.</p>
<h2 id="the-fix-one-renderer-not-two">The fix: one renderer, not two</h2>
<p>Once both clients turned out to want the same shape — a concise always-loaded guidance file plus one <code>SKILL.md</code> per skill — Bimaaji stopped maintaining separate Claude and Codex renderers and introduced a shared base class both transformers extend. Each subclass supplies only two things:</p>
<ul>
<li>its client id (<code>claude</code> or <code>codex</code>)</li>
<li>its guidance file&rsquo;s title line</li>
</ul>
<p>Everything else — the per-skill file layout, whether frontmatter is required, the guidance index, and a provenance footer — comes from the shared renderer plus a small per-client capabilities lookup (skill file paths, whether frontmatter must sit at byte zero, and so on).</p>
<p>That provenance footer is the detail worth stealing for your own installers. Two pieces of metadata do the work:</p>
<ul>
<li>Every generated skill file carries an HTML-comment footer with the <strong>sha256 of the whole skill inventory</strong> it was rendered from.</li>
<li>The guidance index lists each skill&rsquo;s own <strong>source sha256</strong> next to its target path.</li>
</ul>
<p>Together they let you <em>prove</em>, rather than assume, that Claude and Codex regenerated their skill files from the same canonical source — and that the two clients&rsquo; output is byte-identical for the same input.</p>
<h2 id="claude-code-vs-codex-side-by-side">Claude Code vs. Codex, side by side</h2>
<table>
	<thead>
			<tr>
					<th></th>
					<th>Claude Code</th>
					<th>Codex</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Always-loaded guidance</td>
					<td><code>.claude/CLAUDE-WAASEYAA.md</code> (kept separate from a consumer&rsquo;s own <code>CLAUDE.md</code>)</td>
					<td>root <code>AGENTS.md</code></td>
			</tr>
			<tr>
					<td>Per-skill file</td>
					<td><code>.claude/skills/&lt;skill-name&gt;/SKILL.md</code></td>
					<td><code>.agents/skills/&lt;skill-name&gt;/SKILL.md</code></td>
			</tr>
			<tr>
					<td>Discovery key</td>
					<td>directory name</td>
					<td>directory name</td>
			</tr>
			<tr>
					<td>Frontmatter required at byte zero</td>
					<td>yes</td>
					<td>per capability lookup</td>
			</tr>
			<tr>
					<td>Command name source</td>
					<td>directory name, not frontmatter <code>name</code></td>
					<td>directory name</td>
			</tr>
	</tbody>
</table>
<h2 id="what-this-means-if-youre-building-similar-tooling">What this means if you&rsquo;re building similar tooling</h2>
<ul>
<li><strong>Don&rsquo;t trust your own success counters.</strong> A &ldquo;files written&rdquo; count that doesn&rsquo;t check whether the client&rsquo;s discovery mechanism actually finds those files will lie to you convincingly.</li>
<li><strong>Cite the client&rsquo;s own docs, not an issue description.</strong> Bimaaji&rsquo;s changelog is explicit that the Codex per-skill layout only shipped once there was a citable, verified discovery mechanism from OpenAI&rsquo;s own docs — not because it seemed like a reasonable guess.</li>
<li><strong>One renderer beats one renderer per client</strong> once you notice two clients want the same shape. Two copies of &ldquo;how a skill file gets rendered&rdquo; is exactly the kind of thing that drifts quietly.</li>
</ul>
<p>Baamaapii</p>
]]></content:encoded></item></channel></rss>