# Your Claude Skill Is Invisible to Codex. Here's How to Fix It.

> Source: <https://dev.to/agentiknet/your-claude-skill-is-invisible-to-codex-heres-how-to-fix-it-3l74>
> Published: 2026-07-14 01:36:24+00:00

Disclosure up front: I build

[agentproto], whose spec

registry (the AIPs) is the last third of this piece. The problem in the first

half stands on its own, and the walkthrough uses real, checkable commands.

Corrections welcome — file an issue.

You spent an afternoon writing a good skill. A `SKILL.md`

, a couple of scripts,

a crisp description so the model knows when to reach for it. Claude Code picks it

up and uses it perfectly.

Now open Codex in the same repo. Nothing. The skill is invisible — wrong folder,

wrong format, wrong dialect. Point a cheap local model at the task and you get

the same blank stare. You wrote the capability once, and exactly one agent can

see it.

The one idea, if you remember nothing else:

Everyone converged on folders of markdown with zero interop. It's Ethereum

before ERC-20 — the primitive is proven, and nothing can hold anyone else's.

Open any serious agent-driven repo in 2026 and you find the same sediment: a

`CLAUDE.md`

, an `AGENTS.md`

, maybe a `GEMINI.md`

saying mostly the same thing; a

`.claude/skills/`

folder full of `SKILL.md`

; Codex agents in TOML; a `.mcp.json`

;

somebody's `OPERATOR.md`

. Every tool independently discovered the same primitive

— **agent behavior configured as files in the repo** — and every tool speaks its

own dialect of it.

This is a genuinely good primitive, and the convergence is evidence it's right.

Files are diffable, reviewable, versionable; they ride along in git; agents can

read *and write* them, which is what lets an agent improve its own tooling.

Anthropic's harness team, describing their long-running app builder (March

2026), put it plainly: **"communication was handled via files."**

Repository as constitution.Here's why this shape won: each new agent

session arrives like a new contributor with shell access but no knowledge of

your team's norms, so a short`AGENTS.md`

acts as the repo's constitution for

agents. The pattern is settled. The interop is what's missing.

The dialects are the whole problem. They don't even agree on names: it's

`skill.title`

in one flavor, `skill.name`

in another, three incompatible spins on

`AGENTS.md`

. A capability you wire into one product's config is invisible to the

other four agents in your fleet — so *you* re-wire it, by hand, every time you add

a brand.

**That manual re-wiring, with your name on it, is the interop tax — and it's the
part of "orchestration" nobody sells you a fix for.** Before we build one, do the

Where are you?0 duplicated declarations— you're single-agent, not

your problem yet.2–3(a`CLAUDE.md`

here, an`AGENTS.md`

there) — you're

paying the tax quietly, once per new brand.4+— youarethe interop

layer, by hand, and it costs an afternoon per new agent.

Watch where the platform layer is heading, because it validates the whole idea.

Anthropic's Managed Agents (April 2026) virtualizes the *runtime*: the session is

an append-only log, the harness is disposable, the sandbox sits behind one

generic `execute`

interface. Stable contracts between layers, so each layer swaps

freely.

Design it like an OS.The Managed Agents write-up is explicit about the

principle: to build infrastructure that accommodates "programs as yet unthought

of," you"decouple the brain from the hands via a uniform tool interface"and

put stable interfaces over swappable implementations.

That's exactly the right instinct — and it's hosted, and it's Claude-only. The

same layering, done in the open, is just as valuable one floor *below* the

runtime: stable contracts for the **files**. What a tool promises, how a driver

implements it, what a skill declares. Make those contracts public and versioned,

and any host can load any capability — the way any wallet holds any ERC-20.

So let's actually build one and watch it reach three different agents.

The trick is to split what most formats fuse. A capability is two things: a

**contract** (its name, its inputs and outputs, whether it's allowed to mutate

anything) and an **implementation** (the code that runs). Fuse them and the

capability is welded to one runtime. Separate them and the contract is the part

that ports.

Here's a docs-search tool as a pure contract — agentproto's `defineTool`

(the AIP-14 `TOOL.md`

spec). Note what's *not* here: no execute body.

``` js
// tools/docs-search/TOOL.ts — the contract, and nothing else
import { defineTool } from "@agentproto/tool"
import { z } from "zod"

export const docsSearch = defineTool({
  id: "docs.search",
  description: "Search the team's internal docs. Returns titles + URLs.",
  inputSchema: z.object({ query: z.string(), limit: z.number().default(5) }),
  outputSchema: z.object({
    hits: z.array(z.object({ title: z.string(), url: z.string() })),
  }),
  mutates: [],        // read-only → no approval gate needed
  approval: "auto",
})
```

The contract carries identity, schemas, and a *side-effect profile* — `mutates`

and `approval`

are how a supervisor later decides whether this call needs a human

(read-only tools sail through; a tool that writes files gets gated). One file,

one declared promise, zero opinion about how it's fulfilled.

**This is the piece that makes a capability portable: a promise any runtime can
read without running anyone's code.**

Now the code. A **DRIVER** (AIP-30's `defineDriver`

) bundles one or more

implementations, each bound to a tool contract by `implementTool`

. The binding is

type-checked against the contract's schemas.

``` js
// drivers/docs-meili.ts — one implementation of the contract above
import { defineDriver, implementTool } from "@agentproto/driver"
import { docsSearch } from "../tools/docs-search/TOOL.js"

export default defineDriver({
  id: "docs.search.meili",
  name: "Docs search via Meilisearch",
  kind: "http",
  implementations: [
    implementTool(docsSearch, async ({ input }) => {
      const res = await fetch(`${process.env.MEILI_URL}/indexes/docs/search`, {
        method: "POST",
        body: JSON.stringify({ q: input.query, limit: input.limit }),
      })
      const { hits } = await res.json()
      return { hits: hits.map((h) => ({ title: h.title, url: h.url })) }
    }),
  ],
  network: { egress: ["MEILI_URL"] }, // declared reach, not ambient
})
```

The codebase makes the analogy for you. The `implementTool`

doc comment calls it

*"equivalent to Solidity's MyToken is IERC20 pattern"* — the compiler enforces

`docs.search`

keeps working.

Why the split earns its keep.A driver declares its own`network.egress`

,

its auth, its install steps — so the same`docs.search`

contract can have a

local implementation, a hosted one, and a mock for tests, and the resolver

picks one per call. That's "stable interfaces over swappable implementations,"

but foryourtools, inyourrepo, not behind a vendor's API.

Two files. Now the payoff.

Start the daemon in your repo. It reads your `tools/`

and `drivers/`

and exposes

them over MCP:

```
npm i -g @agentproto/cli
agentproto install claude-code          # also installs the adapter package
agentproto serve                        # long-lived daemon, serves the /mcp gateway
```

Now spawn agents. Each adapter is pointed at the daemon's `/mcp`

gateway as it

starts, so all of them see the same served tools — including your `docs.search`

:

```
# a frontier agent…
agentproto sessions start claude-code --cwd . \
  --prompt "Use docs.search to find our retry-policy page, then summarize it."

# …the exact same tool, a different vendor…
agentproto sessions start codex --cwd . \
  --prompt "Use docs.search to check whether we document the queue timeout."

# …and a cheap local model, no MCP config of its own
agentproto sessions start hermes --cwd . \
  --prompt "Use docs.search for 'deploy rollback' and list the top 3 hits."
```

**One contract, one driver, three vendors — Claude Code, Codex, and a local
model via Hermes all call docs.search with no per-agent wiring.** The daemon is

This is the answer to the question [the hub piece](https://dev.to/agentiknet/you-can-parallelize-the-typing-you-cant-parallelize-the-trust-2fkd)

left open — *when you give one agent a new capability, how many of the others get
it?* Here the answer is "all of them, for free," and that's the difference between

The same "one place, every agent" trick works for tools you *didn't* write. MCP

servers are the industry's one real interop win — but each agent brand configures

them separately, so a server wired into Claude Code is still invisible to Codex.

agentproto imports an MCP server once into the daemon's curated set, and then

every session can reach it. The flow is three real tool calls:

```
mcp_discovered_list      → find MCPs already configured in claude/cursor/etc.
mcp_import               → snapshot one into the daemon (survives the source
                           config being deleted later)
mcp_imported_tool_list   → search-then-call: list the imported server's tools…
mcp_imported_call        → …and invoke one
```

The import captures a *snapshot* at import time, so the tool stays usable even if

you later remove the original config. **You wire an MCP server up once, in one
daemon, and Claude Code, Codex, and your local model all inherit it** — instead of

`.mcp.json`

block into four different agent configs and keepingThat's the whole interop tax, refunded: author-once for tools you write, import-

once for tools you borrow.

Here's the honest edge, because that's what makes the rest trust me. You could do

all of this with a bespoke framework. The bet agentproto makes is *not* a

framework — it's a registry of numbered specs, modeled deliberately on ERCs, BIPs,

and PEPs. `TOOL.md`

is AIP-14. `DRIVER.md`

is AIP-30. Skills, operators,

workflows, policies, sandbox definitions each get a number.

The reason to prefer numbers over a framework is projection. A contract that's a

public spec, not a class in someone's SDK, can be adapted to any host:

`toMastraTool(impl)`

for a Mastra agent, or
`toAiSdkTool(impl)`

for the Vercel AI SDK,`TOOL.md`

(AIP-16 declares the IO as JSON Schema, no compiled module required).

Aligned-with, not forked-from.A Claude Code skill is already most of an

AIP skill; the specs are meant to standardize the format people converged on,

not replace it. And they'reours, plural: Apache-2.0, open to amendment by

issue — the entire point of a numbered public registry is that no single vendor

owns the meaning of`docs.search`

.

The honest caveats, stated plainly: agentproto is **0.5.0-alpha**. The daemon, the

MCP surface, the driver doctype, and MCP import are live and hands-on today; the

in-process Mastra / AI-SDK adapters and the wider ~52-spec family are earlier-stage

— the repo publishes a live-vs-roadmap split precisely so you can check. Betting on

a young registry is a real cost. So is re-wiring the same tool by hand forever.

Pick your poison with open eyes.

Once a capability is *files with a contract*, the loop closes in a way no config

format allows. An agent can **write** a new `TOOL.md`

, bind a driver, or scaffold

a skill — and because those are file writes, they're diffs you can gate exactly

like any other code.

This is where this piece hands off to [the supervision ladder](https://dev.to/agentiknet/your-agent-says-the-tests-passed-it-didnt-run-them-15j):

stage the agent-authored tool behind a check and a human ack, and your fleet's

capabilities grow the way your codebase grows — incrementally, reviewed, in git —

instead of the way config sprawl grows. The daemon even exposes the doctype verbs

(`create_tool`

, `create_driver`

, `list_driver`

, `self_inspect`

) *as MCP tools*, so

an agent authors its own next capability through the same interface it uses to

call the last one.

**That's the actual endgame of files-with-contracts: not tidier config, but agents
that safely extend themselves, under the same review discipline as a human PR.**

You don't need my daemon to start paying down the tax:

Count your capability re-declarations one more time. Every number above one is a

place a dialect can drift, an agent that's blind to a tool it should have, and an

afternoon of your life spent being human glue. The pattern is settled; the

plumbing is the only thing left to build — and it's a couple of files, not a

platform migration.

We had folders of markdown and called it interoperability. It never was. The fix

isn't another framework that everyone reinvents next quarter — it's a contract

anyone can read and no one owns.

If I've mis-described how your agent stack handles this, or you've solved the

interop tax a cleaner way, tell me where — I'll fix the piece.

Ten pieces, one argument. Start anywhere; each one cross-links the rest.

| Piece | The one idea | |
|---|---|---|
| 1 |
|

*Written by the maintainer of agentproto (Apache-2.0, source). Same contract as our /compare page — dated facts, named strengths, corrections by issue. Got something wrong? File an issue.*

*Building agentproto in the open — follow @theagentproto and @agentik_ai on X.*
