The more I built with AI coding agents, the more I ended up depending on them, and eventually this looked like a pretty big risk. If a vendor increased their prices, went down for any reason, or let its model fall behind, my projects would've been left exposed. So I wanted to remove this risk, or at least reduce it drastically. I wanted to be able to switch vendor, or run a few side by side, without having to redo my entire setup.
This is why I've been working on setting up mechanisms to give me that freedom.
Tools used
- AI tooling
- Claude Code
- Codex CLI
- Antigravity CLI
- Meta layer
- AGENTS.md
- Protocols
- Skills
- Sync harness
- Sync scripts
- Pre-commit hook
- GitHub Actions CI
Picking one source (and why that was only the start)
The first thing I ran into was that each agent looks for its own rules file. Claude Code reads a CLAUDE.md, while Codex and Antigravity are looking for an AGENTS.md file instead. So if I wanted all three to follow the same rules, I had to keep the content in both files at once. Keeping the same thing in two places by hand isn't sustainable and can easily drift. Sooner or later, I'd update one and forget the other, and my agents would end up using different rules without me noticing.
So the first thing I did was pick one file to be the source of truth and have the rest follow from it. I went with AGENTS.md for that as it's the closest thing we have to a shared standard right now, and I'd rather build around something vendor-neutral than tie everything to one tool's preference. After that, the rest was pretty simple. Codex reads AGENTS.md on its own, nothing to set up here. Antigravity just needed a single line of config to point it at the same file. And CLAUDE.md is simply a copy that gets regenerated from AGENTS.md automatically, with a banner at the top reminding me not to edit it by hand. I write the rules once, in one place, and everything else follows.
One source, everything else generated
The whole idea is that I only ever edit one file, AGENTS.md, and every other agent's rules file gets generated from it. The generated ones aren't meant to be touched by hand, since that's exactly what would put me right back where I started. One place to make a change, and the rest follows.
If my rules had actually been only this one file, that would've been the end of it. But they weren't. The real substance lived in my skills, the routines I had set up for things like how a feature gets built or how a change gets reviewed. The problem was that this substance was tangled up inside the skills themselves, mixed in with the part that fires them instead of sitting somewhere on its own. Syncing that one file only handled the easy part. What actually mattered was still buried in there, and that's where the real design work started.
Pulling the substance out of the skills
Fixing the portability of my artefacts started with separating two things that were tangled together: the trigger and the substance. The way I had been building skills, they were both the trigger and the substance at once. The skill was being fired when I asked for something, and it was also where the actual directives lived. The trigger is just the part that fires at the right moment. The directives are the real weight, and there's no reason to keep them buried inside it.
So I started pulling the directives out of the skills. Instead of leaving them inside the skill, I moved them into plain markdown files, one per routine, sitting in the repo on their own. These are what I ended up calling protocols. A protocol is really just a document… here's how a feature gets built, here's how a change gets reviewed, here's what has to be true before anything ships, etc. Nothing about it is tool-specific. It's simply a markdown file, and every agent can read a markdown file.
That's what made the whole thing portable. The skills are still there and still fire when I ask for something, but instead of carrying the directives themselves, they just point at the protocol. And because a protocol is just a file sitting in the repo, a skill isn't the only way to reach it: AGENTS.md points the way to the protocols, so one can be pulled in directly too. Either path lands on the exact same document. There's no Claude copy of how-a-feature-gets-built and a separate one for Codex… there's one file, and if I change it, everyone picks it up the next time they read it.
Whatever fires it, every agent lands on the same protocol. The trigger points; the substance lives once.
What's left of the skill
Once the directives moved into protocols, the skill became pretty thin. What's left is mostly a description of when it should fire, plus a short text that points at the protocols it should read. Here's what one of mine actually looks like, slightly trimmed:
---
name: build-feature
description: Walk the feature-build protocol when adding, creating, building,
or implementing a new feature.
---
# /build-feature
Substance lives in markdowns/protocols/build-feature.md.
Steps:
1. Classify the feature and note its stake tier.
2. Run the near-match scan before writing anything new.
3. ... (each step points to the relevant protocol)---
name: build-feature
description: Walk the feature-build protocol when adding, creating, building,
or implementing a new feature.
---
# /build-feature
Substance lives in markdowns/protocols/build-feature.md.
Steps:
1. Classify the feature and note its stake tier.
2. Run the near-match scan before writing anything new.
3. ... (each step points to the relevant protocol)The description is the line that does the work. The coding tool reads it to decide when the skill is relevant, so when I ask for something that matches, the skill fires on its own and goes to read the protocol. And this isn't a Claude-only trick. All three tools fire skills, and they look for them in the same place: a .agents/skills folder, in a SKILL.md file. It's basically an open standard at this point, the same way AGENTS.md is. Codex scans that folder on its own, Antigravity reads it too, and both pick the right skill by matching its description.
Claude is the one exception, and it's pretty similar to the rules file. It looks for skills in its own .claude/skills folder instead of the shared one, so it gets a generated copy synced over, exactly like CLAUDE.md is synced from AGENTS.md. The way I think about it is that .agents/skills is the shared standard, and .claude/skills is just the Claude adapter. I author the skill once in the neutral spot, and the one tool that looks elsewhere gets its mirror automatically.
Underneath all of it, the protocol is still the thing that carries the weight.
Keeping the copies from drifting apart
There's an obvious risk hiding in all of this… The moment we have a source and a copy generated from it, we've created a way for them to drift apart. If I edit one of the copies by hand, or the copy just doesn't get regenerated properly after changing the source, we're right back to the initial problem: two files which are supposed to match but don't.
To avoid this, I don't treat the copies as something to maintain at all. They're something that only gets rebuilt. Every time I commit, a script regenerates them from the source directly. CLAUDE.md gets rewritten from AGENTS.md, the .claude/skills folder gets rebuilt from .agents/skills, and it all happens as part of the commit itself. I removed the need to remember to do it, and there's no window where the source has moved on but the copy hasn't synced.
The first guard is just a banner sitting at the top of every generated file:
<!-- CLAUDE.md — auto-synced from AGENTS.md by scripts/sync-agents-md.sh.
Do not edit this file directly. Edit AGENTS.md instead; the pre-commit
hook will regenerate this file on the next commit and any edits here
will be lost. --><!-- CLAUDE.md — auto-synced from AGENTS.md by scripts/sync-agents-md.sh.
Do not edit this file directly. Edit AGENTS.md instead; the pre-commit
hook will regenerate this file on the next commit and any edits here
will be lost. -->It's there for the failure I worried about the most: opening a copy, making a quick edit because that's the file I happened to have in front of me, and forgetting it's a copy. The banner is a heads-up before I waste time on a change that will get wiped.
But the banner is only a reminder, not a lock, so the real guard is mechanical. If I edit a copy by hand anyway, the next commit just regenerates it from source and the edit disappears altogether. The source always wins. And since a hook on my machine only helps if it's actually installed, the same checks run again in CI. If a copy doesn't match its source, the build fails and tells me how to fix it. So even if I skip the hook, or clone the repo somewhere it isn't set up, the drift gets caught before it can land.
The one thing that doesn't port
While I've made all of this sound pretty clean, it's worth being honest about where it isn't. Almost everything is portable: the rules, the protocols, the skills. But there's one piece that isn't portable, and that's hooks.
A hook is a script that fires automatically on some event, like right before the agent runs a command or writes a file. I use them as guardrails mostly. The one I care about the most blocks the agent from reading or writing secrets, so an API key never ends up somewhere it shouldn't. The problem is that every tool has its own hook system, and they don't line up adequately. Claude Code currently has around 28 events it can fire on, Codex currently has roughly ten with different names, and Antigravity has its own set again. There's no shared standard here like the rules or the skills.
So a hook I write for Claude only protects Claude. My secret-blocker lives in Claude's hooks, and if I want the same guard running on Codex or Antigravity, I have to write it again, in each tool's format. There's no single file I can point all three at.
| Layer | Ports across tools? | How |
|---|---|---|
Instructions (AGENTS.md) | Yes | One source; Claude reads a synced CLAUDE.md |
| Protocols | Yes | Plain markdown any tool can read |
| Skills | Yes | Shared .agents/skills standard; Claude reads a synced mirror |
| Hooks | No | Each tool's hook system differs; re-authored per tool |
I could try to hide that behind some wrapper that pretends it's portable, but this wouldn't be aligned with the rest of my approach. And honestly, it's something I can live with. Hooks are part of the runtime, not the rules, so they're a smaller and more separate surface than everything else here. The handful of hooks that truly matter for safety, I can simply rewrite them for each tool when needed. Hopefully, at some point some kind of standard will emerge for these too, which we'll be able to leverage.
Closing thoughts
My main objective with all of this was to not be locked in with a single vendor, and this achieves my objective. If a vendor were to raise their prices, go down, or let its model fall behind, I can lean on another and move on without rebuilding anything. The mechanisms which are core to my projects are already ready. With the new capabilities unlocked by AI, risk management is one of the parts that matter the most.
The surprise to me was how little of it was new work: by building on the shared standards instead of one specific tool's format, most of the support was already there. It even lets me do things a single tool can't, like having a different vendor review another's work, since they all run on the same mechanisms.
Keeping the mechanisms in sync is only half of it, though. The other half is keeping track of what each tool can actually do, which drifts fast, but I have some ways to deal with this, which I'll be covering as part of the meta layer series.

