58 days, 374 PRs, two AI agents: here’s what broke

MacBook Pro on top of brown table

Naoto Yamabe has been building a fishing app called World Fishing Map for 58 days. In that time, the repository accumulated 374 merged pull requests. He wrote most of none of it. Two AI coding agents did.

One agent is Claude Code, reading a file called CLAUDE.md. The other is ChatGPT Codex, reading a file called AGENTS.md. Both agents, one codebase, running simultaneously. This is the architecture that kept them from quietly building to different specs.

️ The Setup

World Fishing Map lets you photograph a fish, have an AI identify the species, and log the catch on a world map. The app runs verification checks against each catch: EXIF and GPS cross-checks, perceptual hashing against nearby photos, a water-body lookup, and a hash-chained append-only ledger. Verified catches earn points. Your tier determines how precisely you can see other anglers’ spots.

The stack is Flutter on the front end, FastAPI and PostGIS on the back end, and Firebase for auth. Two humans work on it. Yamabe uses Claude Code. His collaborator, referred to as Mao, uses ChatGPT Codex. Standardizing on one tool would have meant one person working slower. So instead of standardizing the tool, Yamabe standardized the source of truth.

3D rendered ai text on dark digital background

⚠️ The Problem Nobody Warns You About

Each agent reads its own instruction file. That sounds manageable until you follow the implication: your project now has two instruction manuals, and nothing in the system forces them to agree.

Instruction files for coding agents are not documentation. They are closer to configuration. They contain statements like “never grant points from this code path” and “this ledger is append-only, do not add an UPDATE.” When two instruction files drift apart, you do not get a stale README. You get two agents confidently building to two different specs at roughly six pull requests a day.

Yamabe did not reason his way to this problem. He found out the hard way. He had split a large root CLAUDE.md into a root file plus per-directory files for api/, app/, and web/. Then, to onboard Codex, someone created AGENTS.md by copying the pre-split version of CLAUDE.md. It worked immediately, which was the dangerous part. Codex had a complete, coherent set of instructions. They were just the old ones. Every subsequent change to CLAUDE.md widened the gap silently, because nothing in the system knew the two files were supposed to be related.

️ The Fix: One Original, All Others Are Pointers

CLAUDE.md is the single source of truth. AGENTS.md is a pointer. It is not allowed to contain policy.

The root AGENTS.md now opens with something like this:

The source of truth for instructions is CLAUDE.md. This file does not duplicate its content. Duplication guarantees that one copy goes stale — and in fact an AGENTS.md that was copied from a pre-split CLAUDE.md is exactly how that happened. This file holds only “where to read” and Codex-side operating rules.

There is one asymmetry worth knowing: Claude Code automatically reads CLAUDE.md files in subdirectories. Codex does not. So AGENTS.md explicitly instructs Codex to open api/CLAUDE.md before touching api/. The difference in tool behavior is itself something the instruction file has to encode.

Twenty Lines of CI That Enforce the Rule

A rule you cannot enforce is a wish. So the relationship between the files is tested on every pull request. The test checks three things:

  • The pointers exist. If AGENTS.md stops referencing api/CLAUDE.md, CI fails with a message explaining that Codex does not read subdirectory files automatically.
  • The pointers stay thin. A line-count ceiling: 60 lines for directory pointer files, 200 lines for the root. This catches the actual failure mode, which is not a wrong pointer but a growing one. A pointer that quietly expands becomes a second manual. A line count catches that. Almost nothing else does.
  • Internal files stay internal. The web/ directory deploys via Vercel with no build step, meaning anything placed there goes live publicly. Yamabe found his own internal web/CLAUDE.md was live on the public internet. That path is now blocked in two places, and CI checks both.

Here is the structure of that test:

POINTER_DIRS = ("api", "app", "web")

MAX_POINTER_LINES = 60
MAX_ROOT_LINES = 200

def test_root_agents_md_points_to_claude_md() -> None:
    text = _read(REPO_ROOT / "AGENTS.md")
    assert "CLAUDE.md" in text
    for name in POINTER_DIRS:
        assert f"{name}/CLAUDE.md" in text, (
            "Root AGENTS.md is missing the pointer to "
            f"{name}/CLAUDE.md. Codex does not read subdirectory "
            "CLAUDE.md files automatically, so this is mandatory."
        )
    assert len(text.splitlines()) 
lines of HTML codes

Preservation Anchors

The second pattern worth stealing is what Yamabe calls preservation anchors. An AI agent asked to refactor will produce a cleaner, working version that has quietly dropped a feature. It is not deceiving you. It genuinely does not know the thing it removed was load-bearing.

CLAUDE.md includes a dedicated section listing things that must not change, each with a one-line reason and a pointer to where the detail lives. Examples include fraud-detection scoring formulas, the append-only triggers on ledgers, and the rule that consumption entries must carry a null catch ID (because the fraud clawback reconstructs awarded amounts by summing per-catch deltas; break that and a clawback silently under-refunds).

The line that does the real work:

If a change touches a preservation anchor, the tests will fail. When they fail, do not fix the test — first suspect that the change broke the anchor.

That sentence exists because a coding agent staring at a failing test will instinctively try to make it green. Which it is very good at.

What the AI Actually Got Wrong

The failures were not architectural. They were factual. The app ships a species encyclopedia of 2,940 species, each with an illustration and a written description. Almost all of it was AI-generated and cross-referenced against a taxonomic database. Three examples:

  • 410 species carried an incorrect English name. The upstream source lists vernacular names with no preferred flag, so the pipeline sorted and took the first result. That usually produced an obscure regional name for the right fish. Sometimes it produced a different animal entirely. One shark was labeled "School Shark," which belongs to a fish in a different family. Because descriptions were generated before names were corrected, with the wrong name fed into the prompt, 96% of those corrected species had the wrong name embedded in confident prose about the wrong fish.
  • A fish with 1,030 occurrence records all concentrated in one corner of Australia was described as widely distributed across the Indo-Pacific. The occurrence data fed one generator; the description generator received only names and taxonomy. Another species had its family misidentified in the text while the correct family appeared in a column rendered on the same page. That contradiction was live in production for twelve days.
  • Flatfish were illustrated facing the wrong way. Which side a flounder's eyes are on is a real taxonomic property. The illustration generator did not know this. Yamabe audited all 53 species manually, mirrored 20, and found that two of the ones he left alone are pictures of an entirely different fish.

None of these were caught by a test. They were caught by a human looking at fish. That is the honest summary of 58 days at six pull requests a day: the agents made building faster. They did not make being right faster. The bottleneck moved. It did not disappear.

What to Take From This

If you are running more than one coding agent on one codebase, four rules apply:

  1. Pick one source of truth and make the others pointers. Not "keep them in sync." That is a promise you will break.
  2. Test the pointers for size, not just presence. Bloat is the actual failure mode.
  3. Write down what must never be deleted, and say so explicitly in the agent's instruction file. Then tell it not to fix a failing test before suspecting the change broke the anchor.
  4. Assume the facts are wrong, not the code. Your agent will produce structurally sound code full of confidently incorrect content. Budget human review for content, not syntax.

Yamabe is building World Fishing Map during RevenueCat Shipaton 2026 and writing up the process as it happens. Follow along at @WorldFishingMap on X.

Stay on top of AI & Automation with BizStack Newsletter
BizStack  —  Entrepreneur’s Business Stack
Logo