Two Agents, One Codebase

Brett Ridenour Brett Ridenour · March 30, 2026

A few weeks ago I started running two AI coding assistants on the same codebase at the same time.

Not because I like complexity. Because the single-agent approach had started to feel like using one person for everything — the person who thinks hard about your database schema is doing fundamentally different work than the person generating twenty migration files to a spec. Keeping them the same has a cost.

The split: Claude Code for architecture, long-context decisions, anything where judgment matters. OpenAI Codex for the mechanical work — autonomous scaffolding, DevOps tasks, anything with a clear input and a clear expected output.

The honest reason I added Codex: I was hitting the usage limits on my $200/month Claude Max plan. Instead of slowing down, I bought the $200/month Codex plan too. Four hundred dollars a month in AI subscriptions is a lot until you price out what it would cost to hire the equivalent throughput.


Setting up full-auto

Getting Codex on Arch was one command:

pacman -S openai-codex-bin

Full-auto for Codex lives in ~/.codex/config.toml:

approval_policy = "on-request"
sandbox_mode = "workspace-write"
model = "gpt-5.4"

On the Claude side, it’s one flag in ~/.claude/settings.json:

{
  "skipDangerousModePermissionPrompt": true
}

No approval prompts. No pauses. Both running.


The scoreboard

I built a Waybar module that polls both APIs every 60 seconds and renders 5-hour and 7-day usage windows as progress bars in my status bar:

Claude  ▰▰▰▱▱▱  51%  5h↻1h12m  7d↻3d04h
Codex   ▰▰▱▱▱▱  34%  5h↻2h44m  7d↻3d04h

When either window hits 80% it fires a desktop notification. The bars move faster than I expected.


What the agents actually know

This is the part that makes the whole thing work.

The codebase has a CLAUDE.md file at the root. It’s not documentation — it’s a contract. Every agent that touches this project loads it automatically. It contains the rules that took the longest to learn the hard way:

All data scoped by location_id.
Every DB query, API endpoint, and React Query key MUST include location_id.

Money always in cents (integer).
8500 = $85.00. Never floating point.

Quote versions are immutable.
Each pricing change creates a new version. Never mutate an existing one.

Financial ops go through LedgerEventEmitter → BullMQ → Formance.
No exceptions. No SQL fallback.

There are also per-layer skill files baked into the project. The DB agent loads add-migration, which knows the exact migration template, knows to run npm run db:reset against all 44 existing migrations, knows every new table needs a location_id foreign key and a prefixed primary key from generateId(). The API agent loads add-api-endpoint, which knows to build Zod schemas, register routes in server.ts, and verify every service method scopes by locationId — not just the route handler. The frontend agent loads add-frontend-feature, which knows never to use raw fetch(), always import types from @freebo/shared rather than redefining them, and never write SSR patterns into a Vite SPA.

The agents aren’t guessing at conventions. The conventions are in their context before they write the first line.


The team

When I invoke /implement-feature-team against a PRD:

/implement-feature-team docs/PRD-notifications-activation.md

It doesn’t just run one agent. It runs a pipeline.

┌─────────────────────────────────────────────────────────┐
│  LEAD  (reads PRD, surveys codebase, builds context)    │
└────────────────────────┬────────────────────────────────┘

          ┌──────────────▼──────────────┐
          │         DB AGENT            │
          │                             │
          │  supabase/migrations/       │
          │  generateId() for PKs       │
          │  location_id on all tables  │
          │  npm run db:reset           │
          │                             │
          │  outputs: schema summary    │
          └──────────────┬──────────────┘
                         │ schema
          ┌──────────────▼──────────────┐
          │        API AGENT            │
          │                             │
          │  packages/shared/types/     │
          │  apps/api/src/services/     │
          │  apps/api/src/api/v1/routes/│
          │  Zod + OpenAPI schema       │
          │  LedgerEventEmitter         │
          │  npm run typecheck          │
          │                             │
          │  outputs: endpoint surface  │
          └──────────────┬──────────────┘
                         │ endpoints + types
          ┌──────────────▼──────────────┐
          │      FRONTEND AGENT         │
          │                             │
          │  apps/web/client/src/api/   │
          │  apps/web/client/src/hooks/ │
          │  React Query + location_id  │
          │  shadcn UI + Tailwind       │
          │  App.tsx route wiring       │
          │  npm run typecheck          │
          └─────────────────────────────┘

Each agent is a fresh Claude instance with isolated context. The lead does the research — reads 2-3 existing examples of each pattern, checks for naming conflicts in App.tsx, looks for any domain code that already exists. Then it passes a context summary to every downstream agent so none of them have to re-discover the same things.

Between phases, the lead does a micro-review. Before spawning the API agent, it checks that the DB migration includes location_id on every new table and that db:reset passed. Before spawning the frontend agent, it checks that shared types are exported and that packages/shared was built. Small gates that catch the obvious mistakes before they compound.


Running multiples

The part that changes how this feels to work in: you can run multiple feature teams at once.

While one session’s API agent is building out an endpoint, I open a second Claude session on a different branch and invoke the skill again. The lead starts reading a second PRD. The DB agent for feature two starts writing migrations while feature one’s frontend agent is wiring routes.

On a busy morning there might be six or eight subagents active at the same time. Claude is orchestrating each session. Codex is running its own queue of mechanical work in parallel. The Waybar bars fill faster than they used to.

Running two agents forces better prompts. With a single generalist you can be vague and trust it to figure out intent. With specialists you have to decide what kind of work you’re handing off before you type anything. There’s no hiding behind ambiguity.

The scoreboard keeps score. Both bars move. The code writes itself.