Skip to content
Almog Koren
← All writing
Building AI · 7 min read

Why I Moved DogBase to a Monorepo in the Age of AI Coding

I merged all six DogBase repositories into one. Here's why AI coding made the move worth it, and how I set up Claude to work across the whole product.

DogBase Monorepo

People ask me how a small team ships a web app, a mobile app, three backend services, and a set of cloud functions. The honest answer is that AI writes most of the code now. I spend my time on specs, reviews, and decisions.

Last week I made a change that follows from that. I merged all six DogBase repositories into one.

Some background

DogBase is the operating system for working dogs. Police K9 units, search and rescue teams, and military handlers use it to log training, track health, and manage their teams.

Until October, the code lived in six repos. The web app in SvelteKit, the mobile app in Expo, our core backend in Go, an insights service, an AI engine that writes training summaries, and our Firebase functions. Each repo had its own CI, its own deploys, and its own instructions for Claude.

That split made sense when I planned for a team where each person owned one piece. It stopped making sense once Claude became the one writing most of the code.

What six repos really cost

Almost every feature we build crosses repos. When we shipped new pricing, the web app, the functions, and the backend all changed. That meant three specs, three plans, three pull requests, and a written note on which one to deploy first.

Shared logic was copied between repos by hand. Nine files had a "KEEP IN SYNC" header pointing at their twin in another repo. When one copy drifted, nothing failed. We just got a wrong revenue number or a dog birthday on the wrong day.

My Claude setup had the same problem. The same block of workflow rules lived in six CLAUDE.md files. The night before I decided to move, I changed one rule and merged six identical pull requests to do it.

The one that stung most was the one I found while cleaning up after the move. Sixty nine commits of finished mobile work sat on two branches in the old mobile repo: a new home screen, a logbook, timers and a health tab. They were never merged. Nobody was looking at that repo, so nobody noticed.

How the move went

I planned the move the same way we build features. I wrote a spec first and had Claude check it against the real repos before we touched anything. That check caught a problem in my own plan: one fix would have quietly turned automatic production deploys back on.

The move kept every commit, author, and date. All 3,816 commits came over, and we counted before and after to prove it. Releases now carry the app's name, like web/v2.9.0. Each app keeps its own dependencies and deploys on its own. CI looks at which folders a pull request touches, runs only those checks, and ends with one required check.

I split it into two phases on purpose. Phase one was a straight move with nothing else changed. Phase two, still ahead, pulls the shared code out of those KEEP IN SYNC files into one package that both sides import.

Why this fits AI development

AI coding works best when the model can see both sides of a change. If the web app sends a field and the backend reads it, Claude should read both in the same session and change both in the same pull request. With six repos, I was the bridge. I carried context between sessions and made sure the pieces matched.

Now one spec covers the whole feature, with a section for each app it touches. The API contract is written once, in the section for the app that exposes it. The work lands on one branch, in one pull request, and CI checks all of it together.

People worry a big repo will flood the context window. In my case the waste came from my own setup. The web app's CLAUDE.md imported 20 docs, about 100,000 tokens, into every session before I typed a word. As part of the move I replaced those imports with links, so Claude reads a doc only when the task needs it.

Claude Code is built for this. Its guide to monorepos and large codebases describes the layout I ended up with: a root CLAUDE.md that loads at launch, and one per package that loads when Claude starts working in that folder.

Anthropic did the same thing at a much bigger scale

A few days before I finished, Anthropic published how they redesigned source control for their own monorepo. Their merges went from about 2,500 a day in May to more than 30,000 a day in September as Claude took on more of the work. Git couldn't keep up, so a team of seven built their own system, called Scion, and moved the monorepo onto it in five months.

One line from their post stuck with me: "Git assumes that clients work offline and need a complete copy of the repository." When most of your commits come from agents running on servers, that assumption stops holding.

I'm nowhere near that scale, and Git is fine for DogBase. What matters to me is the direction. The company building one of the most capable coding models kept one repo and changed the tools around it. I read that as a strong signal about where software is heading.

How I set up Claude in the monorepo

This is the part people ask about most, so here is the whole setup.

Shell
dogbase/
  CLAUDE.md                        rules for every app
  AGENTS.md                        points other AI tools to CLAUDE.md
  .claude/settings.json            plugins and permissions
  apps/web/CLAUDE.md
  apps/mobile/CLAUDE.md
  services/core-backend/CLAUDE.md
  services/insights/CLAUDE.md
  services/ai-engine/CLAUDE.md
  functions/CLAUDE.md
  docs/

One root CLAUDE.md, about 90 lines. It holds what applies everywhere. A table of every app with where it deploys and how, the rollout order (backend and functions before the web app), and the workflow rules. Never commit on main. Never read a .env file. Make only the change you were asked for.

One CLAUDE.md per app. Each has that app's commands, architecture and rules, from 44 lines for the AI engine to 187 for the web app. Claude loads the root file plus the one for the folder it works in.

One shared workflow. I use the Superpowers plugin, turned on in the repo's settings so every session gets it. Every change goes through the same steps. Brainstorm the design, write a spec, write a plan, write the tests first, review, and verify before anyone says done. Bigger plans run with a fresh subagent for each task and a review after each one.

Specs are history. A spec records what we meant on the day we wrote it. When a feature ships, the spec gets an "Implemented" date and an "As built" section listing where the code ended up different. The doc for that area of the product holds the current truth, and it gets updated in the same branch.

Permissions in settings. Claude can run git status, diffs, tests and builds without asking. It has to ask before running a data migration. It can't read .env files or SSH keys at all.

Skills where they belong. The web app keeps its own design skills in its own folder, so they only load when Claude works on the web app.

Memory for lessons learned. When something bites us, Claude saves a short note so the next session knows. One example: a branch once tracked main by mistake, and a plain push sent 21 commits straight to main and queued a production deploy. We cancelled it in time. Now every commit runs with a branch check in the same command.

Docs that stay true. The repo now has an architecture doc with diagrams in Mermaid and a catalogue of every analytics event. Claude wrote both by reading the code. A CI check fails the pull request if an event in the code is missing from the catalogue. Another posts a warning when code changes and its doc doesn't. The same files serve me, Claude and anyone new who joins.

What happened to my developer guides

Before AI coding I kept a set of developer guides in Monday: coding style, git workflow, rules for our microservices. They were written for people, and by the time I looked again, parts were out of date. One still told you to deploy on App Engine.

Today the CLAUDE.md files are the developer guide. They live next to the code, get reviewed in pull requests like any other change, and get read at the start of every session. The Monday guides were read once, when someone joined.

Why I think this is where software is going

Teams split code into repos because that's how they split ownership. With AI writing most of the code, the thing I plan and review is a feature, and features cross those lines all the time. Design works the same way. Our web and mobile apps should share one design language and one set of types, and that's far easier when both sit next to the specs and docs that describe them.

A monorepo has costs. CI needs path filters, each app needs its own deploy, and at Anthropic's scale you end up building your own source control. For a small team where AI writes most of the code, I think one repo is the right shape. The model sees the whole product, and nothing hides in a repo nobody opened.

If you're running a small product team and thinking about the same move, I'm happy to compare notes.


Sources:

#Building AI

Building something with AI?

Fractional CTO, AI agents, or a rescue for an AI-built app.