Structuring agent config for Claude Code and Codex

How to lay out a personal agent harness that serves two vendors and survives a model upgrade: three layers, one authored source, and rules pushed down into checks rather than prose.

If you run both Claude Code and Codex, you end up maintaining two config trees that describe the same intentions in different syntax — and both of them are full of instructions you wrote for models that have since changed underneath you.

This is the shape I’d recommend instead. It comes out of auditing one long-running personal setup, with the design reviewed twice by the other vendor’s model, so treat the specifics as one data point and the structure as the transferable part.

What the new models changed

Three shifts matter for how you write config, and all three are documented rather than folklore.

They verify themselves. Anthropic’s Opus 5 prompting guide is unusually direct: if your prompt contains explicit verification instructions, remove them — they cause over-verification with no gain in quality — and the same goes for legacy harness scaffolding that adds separate verification steps. It also says not to use subagents to double-check your own work. Most personal configs are carrying a paragraph of exactly this.

Guidance inverts between adjacent generations. This is the one that should change how you write, not just what you delete. The Opus 4.8 guide says that model spawns too few subagents and needs explicit encouragement, and that it interprets instructions literally and won’t infer scope you didn’t ask for. One generation later, both are reversed: delegation needs a cap, and scope needs constraining.

So a config that says “never delegate” will age exactly as badly as “always verify” already did.

Write conditions, not verdicts. This is the structural consequence. “Delegate when the track is substantial and independently ownable” survives a model swap and can be read sensibly by either vendor’s model. “Never delegate” is a bet on one generation’s failure mode. State the threshold and let the model apply it.

Effort is the cost dial. Reach for the effort parameter before prompt gymnastics — and re-run a sweep after a model upgrade rather than carrying old defaults forward.

Three layers, and what belongs in each

The most common structural mistake is a single global instruction file holding all three of these at once.

LayerHoldsRead by
Shared coreScope and authorization boundary, delegation threshold, who owns validation, safety invariantsBoth, identically
Provider adapterTool wiring, hook events, permission syntax, plan mode, team mechanicsOne vendor
Model notesMeasured compensation for an observed failure, with an expiry dateOne model

Keep the core small and provider-neutral, and materialize it into both CLAUDE.md and AGENTS.md. Keep adapters thin. And default to not having the third file at all — most of what looks like model-specific tuning is actually a contradiction in the core that a model is faithfully following.

The specific thing to keep out of the shared core is model-tier policy. “High tier coordinates, low tier implements” assumes a capability step-down that doesn’t exist once you’ve pinned every role to the same model, which is what most people have actually done.

One authored source, generated views

Don’t keep a copy of each skill per vendor with a lint to catch drift. The drift is something you created and are now policing. In the setup I audited, two copies of the same workflow skill had diverged by 46 lines and named different executables — so the same command did different things depending on which CLI you typed it into.

Author once. Generate ~/.claude and ~/.codex from it. Then set an ownership rule for the generated files, because both vendors write machine state into the same config you’re generating: your repo owns the keys you author; the runtime owns everything it writes — marketplace snapshots, trust hashes, plugin enablement state — and unknown keys default to runtime-owned.

Skills are knowledge; plugins are distribution

These are different units and it’s worth being deliberate about which one you’re reaching for.

A skill is one procedure that loads on demand. The useful heuristic from the docs: when a section of your contract has grown from a fact into a procedure, it wants to be a skill — the body costs nothing until it’s used.

A plugin is the packaging unit. It carries skills, hooks, and MCP servers together, and it’s what marketplaces distribute.

Two cross-vendor facts worth knowing before you design around this, both checked on Codex 0.147 and Claude Code 2.1.170:

  • Codex reads Claude’s plugin manifest. It resolves .claude-plugin/marketplace.json, including relative plugin sources, and synthesizes its own adapter on install. One manifest can serve both. See Codex’s plugin and skill docs for its side.
  • Codex plugins don’t carry roles. Its plugin spec covers skills, hooks, MCP and apps; roles are TOML and live elsewhere. Any design that ships role definitions inside a plugin is broken on the Codex side.

One caution on packaging: relative paths don’t survive it. Plugins get copied into isolated version caches, so a plugin referencing ../shared/roles/ breaks on install. Anything shared has to be materialized into each package.

And before you plan to split your skills into a public repo and a private one — measure the coupling first. Of 35 hand-written skills in the setup I audited, exactly one had no references to private paths, private repos, or a personal notes vault. That’s a decoupling project, not a packaging one.

Push rules down into checks

Prose describing a rule is not enforcement. If a constraint can be expressed as a check — eligibility filters, protected paths, merge safety, schema validation — write the check and let the config point at it. A rule stated in three places and enforced in none is the normal state of a mature personal harness.

The corollary: your config is software, and the reason it has no tests is that it looks like documentation. The longest-standing bug I found wasn’t an instruction at all. It was an installer that copied skills with errors suppressed and wrote its success marker unconditionally, so four skills had been missing from every automated run for months while the install reported success every time. Nothing in the prose was wrong. Nobody had ever run it anywhere but a laptop.

Gotcha: hosted sessions don’t read your disk

(Added after publication, because fixing that installer taught us something better than the fix.)

We rewrote the installer properly — expected-name manifest, fail-closed marker, tests pinning the old bug — and then probed the hosted environment it was supposed to serve. It can never work there. Not buggy: structurally impossible.

Two diagnostics inside a scheduled cloud session showed why. Tools the environment setup script installs onto PATH persist from the build, but every entry in ~/.claude is timestamped at session start — the harness reconstructs the config directory per session, after your setup script has run. Anything the script installs there is discarded before the model loads a single skill. Hosted sessions get their skills from the provider’s account sync instead (they arrive in a skills/synced/ directory the harness owns), plus whatever ships inside the repo it checks out.

The general rule: for any environment you don’t own, find out which surfaces are delivered — the checked-out repo, binaries baked into the image — and which are provisioned by the harness, and only ever ship config through the delivered ones. An install step targeting a harness-provisioned path is the worst kind of bug: it reports success on every run, and locally it even works.

Progressive disclosure

The always-loaded contract should hold invariants and routing pointers. Everything procedural should load when it’s needed.

The usual bloat is catalogs — lists of your own commands, skills, and agents written into the contract, when the runtime already discovers them. That text is spent on every session before the task is known.

Parallelism, last

Once the config is honest, decide where parallel agents actually help. Subagents are for focused work where only the result matters; agent teams are for tracks that need to talk to each other. Teams are experimental and off by default — see settings for the flag.

The lever most people want: workers don’t inherit the coordinator’s model, so you can put an expensive model in the coordinator seat and cheaper ones on the volume. If your role definitions already pin a model, spawning workers by role gets you that split with no new configuration.

Two things worth being honest about. This is budget-shifting, not saving — parallel workers use more total tokens, and the win is only that your scarcest tier spends its budget on judgment. And workers typically inherit the coordinator’s reasoning effort, fixed at spawn, so turning the coordinator up turns everyone up.

There’s also a nice inversion here. “Coordinate, don’t implement” is wrong baked into a worker’s definition — that’s the cascade the Opus 5 guidance tells you to delete — and right for a coordinator. Same words, opposite correctness depending on which seat the agent is in. Scope instructions to the seat, not to the system.

The shape, and where to start

core/           shared, provider-neutral: boundaries, thresholds, validation
adapters/       claude/ and codex/: tool wiring, hooks, permissions
skills/         one procedure each, loaded on demand
checks/         the rules that can be executed instead of described

If you only do three things: delete the standing verification instructions, replace every prohibition with a threshold, and run your installer somewhere that isn’t your laptop.

Then have the other vendor’s model review the result — the findings are genuinely independent, because the reviewer has no attachment to your design. Just verify what it tells you before acting. In our second round the reviewer reported a GitHub token invalid; re-run outside its sandbox, the token was fine, and the sandbox had simply blocked keychain access. A reviewer’s report is a claim, not evidence.


One setup, n=1, and the version numbers will be stale by the time you read this. The two failure directions — instructions written for a model that changed, and plumbing nobody ever ran anywhere else — won’t be.