Kishore Kanthan
Article · · 4 min read

One local setup for every coding agent

One rules file, a repo file and global git hooks. Claude Code and Codex get the same rules and checks.

One rules file reaches both agents. The same git hooks check every commit from either one.

TL;DR

  • Write the rules once, in one file, in a small git repo.
  • Point each agent at that file. Claude Code imports it. Codex reads it through a link.
  • Keep the facts of each repo in that repo’s AGENTS.md. Both agents read it.
  • Put the checks in global git hooks. Git does not care which agent made the commit.
  • One install script sets up a new machine, for both agents.

The problem

I use more than one coding agent, mostly Claude Code and Codex. At first, each one had its own rules file, written by hand in different words. The two files drifted apart. One agent followed a rule that the other did not know.

A second agent should not need a second copy of the rules. So the setup has one source for each thing, and each agent points at it.

One source for each thing

Each piece lives in one place, and each agent reaches it in its own way.

One rules file

All the rules live in one RULES.md. It sits in a small git repo of its own, so every change is reviewed and can be undone. It holds hard rules, not wishes: “never” is easier to check than “try not to”.

Keep this file short. It is the always-on core, and every session pays to read it. The detail loads only when a task needs it.

Point each agent at it

Claude Code reads ~/.claude/CLAUDE.md, and that file is one line: an import of RULES.md. Codex reads ~/.codex/AGENTS.md, and that file is a link to RULES.md. A change to the rules reaches both agents at once.

Settings that belong to one tool, such as the model name, stay in that tool’s own config. Rules never go there.

Repo facts in the repo

Each repo has an AGENTS.md at its root. It holds only what is true of that repo: the gate command, how tickets are numbered and where secrets live. The repo’s CLAUDE.md is one line that imports AGENTS.md. Codex reads AGENTS.md directly, so the repo needs no second copy.

Detail on demand

The rules for project work are longer: tickets, tiers, tests, branches and pull requests. They live in a skill, not in the rules file. The rules file says to load that skill before changing code in a repo.

Claude Code loads it as a skill. The rules file also names the skill file’s path, so an agent with no skills reads it there.

Checks every agent must pass

A rule in prose holds only as well as the agent reads it. A check holds for every agent. The best place for a check is one that every agent must pass through. For commits, that place is git.

Set the hooks path once, globally. Then the same hooks run in every repo and worktree on the machine:

Both hooks run for every agent and every person. Either hook can stop the commit.

The subject must start with a ticket key. A T-NNN key must also have its ticket file in the repo. Some changes are too small for a ticket. Docs-only commits pass. A trivial: commit passes if it adds and deletes 10 lines or fewer. A commit on main needs a named escape hatch, ALLOW_MAIN_COMMIT=1. The pre-commit hook logs each use. The hatch is for a person, so the shell guard refuses it.

A repo can set a hooks path of its own, which replaces the global one. Its own hooks must then call the global hooks.

Git can also skip its hooks, with --no-verify or a different hooks path. The shell guard below refuses both, but a guard that reads text can be fooled. So run the same checks again in CI, where no local flag can skip them.

Guard the shell

Hooks on commits do not stop a command that deletes data. This is the one piece that each agent does in its own way.

In Claude Code, two filters check each shell command before it runs:

Two filters in Claude Code check each shell command. It runs only if neither refuses it.

The deny list covers the worst, such as a recursive force delete, dropping a database and removing Docker volumes. The guard refuses more, such as git add -A, git stash pop, --no-verify and DROP TABLE. It also refuses shell writes to its own files and to the agent’s settings.

The guard fails closed. If it cannot read a request, it refuses the command. If it cannot parse a command, it checks the raw text instead. It allows ordinary work, such as deleting one named file.

The guard reads text, so it is a speed bump, not a wall. A command built at run time can get past it. The deny list and the git hooks stand behind it.

Codex gets the same bans in its own command rules. Those rules match only the start of a command, so they catch less than the guard. The git hooks stay the floor for every agent.

A new machine in one step

One install script sets up the machine from the repo. It is safe to run again, and it never overwrites a real file.

The repo holds each piece once. The script sets up the machine for both agents.

The core of the setup is three lines, and the script does the work of all three:

echo "@~/dotfiles/RULES.md" > ~/.claude/CLAUDE.md
ln -s ~/dotfiles/RULES.md ~/.codex/AGENTS.md
git config --global core.hooksPath ~/dotfiles/hooks

Test it

Test the setup the way you test code. In a scratch repo, try each thing it must block:

Each block must fire with a clear message, and a docs-only commit must still pass.

If a block does not fire, the rule is advice, not a control.

What I learned

  • One file stops the drift. Two agents with two rules files will disagree, sooner or later.
  • Point, do not copy. An import or a link costs one line, and it never goes stale.
  • Check where every agent must pass. Git hooks run for any agent, including the next one I try.
  • Keep the always-on file short. Load the detail only when a task needs it.

The same ideas work at team scale, in a shared repo with CI. Read how to set up AI governance for any repo.