Making your dev environment work for AI agents: a field guide

The repo layout, the commands and the rules that let five or more coding agents share one laptop's stack, using prior art from GitHub and Shopify.

There are two engineers at my startup: me and the founder. On a normal day, five or more AI coding agents work alongside us in their own checkouts. That makes agents the main users of our dev environment, and they have no patience and no memory. A rough edge a human works around without noticing is one an agent fails on every time.

This guide covers what I set up so they can run the whole stack on their own. None of the ideas are new. Most come from patterns that big engineering orgs have used for years. What's new is that agents make them mandatory.

Prior art worth copying

GitHub's "Scripts to Rule Them All" (2015). Every repo gets the same small set of entry points: script/bootstrap, script/setup, script/update, script/server, script/test. You don't need to know a repo's language or tooling to run it, only the verb. For an agent, this matters more than anything else on this list: one obvious way to do each job.

Shopify's internal dev tool. It extends the same idea across many repos. One CLI on everyone's machine, with dev up reading each project's config and installing and starting whatever that project needs. The engineer learns one tool, not one setup per repo.

The workspace (meta) repo. In a polyrepo org, one repo exists only to hold the others together. You clone it first, and it clones and runs the rest. It's the cheap alternative to a monorepo: each service keeps its own repo, history and CI, and one place still knows how they fit together.

We use all three: a workspace repo that provides one CLI, dev, with Scripts-to-Rule-Them-All verbs for the whole stack.

The layout: a dev repo and an infra repo

The product spans several repos (an API, the frontends, a data pipeline). Two more repos hold no product code:

Keeping them apart means local tooling never ships to production, and deploy config never ends up on every laptop. Each repo has its own instruction file, so an agent working on deploys reads the infra runbooks, not the local dev rules.

The dev repo looks like this:

workspace/
  dev/                      ← clone this first
    bootstrap.sh            ← installs everything, safe to re-run
    bin/dev                 ← the CLI
    repos.txt               ← every repo: name, branch, install command
    mise.toml               ← pinned Python, Node, pnpm, Poetry
    compose.stores.yaml     ← Postgres, Mongo, Elasticsearch, Qdrant, auth emulator
    process-compose.yaml    ← service dependency graph + health checks
    CLAUDE.md               ← the agent rules
  api/  frontend/  data-pipeline/  …   ← cloned next to it by bootstrap

Setup on a new machine is two commands: git clone the dev repo, then run ./dev/bootstrap.sh. It installs system tools, pins the toolchain with mise, clones every repo in repos.txt next to itself, installs each repo's dependencies, and puts dev on your PATH.

The verbs

dev up <services>    start these and everything they depend on; block until healthy
dev down             stop everything, keep data
dev status           what's running, where
dev logs <svc> -n N  recent logs
dev doctor           what's missing and what breaks without it
dev reset --yes      wipe local data and reseed
dev e2e <suite>      run an e2e suite on its own test stack
dev update           fast-forward every repo
dev pipeline <cmd>   run a data-pipeline job against this copy's stores

These are the same verbs as Scripts to Rule Them All, plus the ones agents kept getting stuck on. Each one has a single job and works the same in every checkout.

The rules

1. up blocks until healthy, and failures bring their logs

A start command that returns as soon as processes launch leaves "is it ready yet?" to the caller. Humans watch logs. Agents run sleep 30 and hope.

dev up web starts web plus its dependencies (stores, seed data, API) and returns only when every one passes its health check. If one fails, it exits non-zero and prints that service's last 50 log lines. The agent learns why something failed, not just that it did.

How: don't write health checks yourself. process-compose already tracks each process's readiness and reports it as JSON. The wait loop asks every two seconds, and it's about 20 lines of bash and jq.

2. Everything that reports state takes --json

Agents scrape human-formatted output badly. dev up, dev status and dev doctor all take --json:

{
  "slot": 1,
  "mode": "local",
  "services": [
    { "name": "web", "status": "Running", "ready": true, "url": "http://localhost:3010" }
  ]
}

In local mode it also includes a test login, so an agent can sign in to the app it just started. How: build the human output from the JSON, never the other way round, so the two can't drift apart.

3. Isolate every copy: ports, data and the lock

Agents that need a running app each get their own copy of the stack, up to three per machine. Agents that only edit code or run unit tests don't need one. When all three are taken, dev up names the holders and the next agent waits for a dev down.

Ports: each workspace claims a slot, and every port shifts by ten times the slot number, so web runs on 3000, 3010 or 3020. Every command prints its URLs, and the agent rules say read URLs from the output, never hardcode them. Otherwise an agent tests localhost:3000, hits another agent's copy, and reports a fix that isn't one.

Data: each slot has its own Docker volumes, so dev reset --yes wipes only that agent's data.

Locking: agents start at the same moment far more often than humans do. Instead of a lock file or a daemon, use mkdir:

for n in 0 1 2; do
  mkdir "$SLOTS/$n" 2>/dev/null && { echo "$n"; return; }
done

Creating a directory is atomic: if two processes try at once, exactly one succeeds. dev down removes it, and a slot whose checkout has been deleted is reclaimed on the next claim.

4. Never wait for a human who isn't there

A "y/N" prompt hangs an agent until something times out. So does a login that opens a browser tab nobody will click.

[ "$JSON" != 1 ] && [ -t 0 ] ||
  die "not logged in: run the login command in a terminal first"

[ -t 0 ] checks whether a real terminal is attached. If not, the agent gets an error it can pass on to you.

5. doctor checks, bootstrap installs, and nothing else installs anything

dev never installs anything. If something's missing, dev up stops and lists exactly what (a tool, a repo, a dependency), and dev doctor --json checks everything, including which secrets are missing and which features break without them. bootstrap.sh is the only thing that installs, and it's safe to re-run.

This split matters for agents. Something that silently installs things halfway through a run is a side effect an agent can't reason about, and a clear "missing: poetry, run bootstrap" is something it can act on.

6. Updates that refuse to make a mess

dev update fast-forwards each repo on its tracked branch, but only if the repo has no uncommitted changes and is on that branch. Everything else is reported and skipped. It reinstalls dependencies when lockfiles change. An agent can run it without ever needing to resolve a merge it didn't create.

7. Write the rules where agents read them

Agents read a project instruction file before they start: CLAUDE.md for Claude Code, AGENTS.md for others. Ours is in the dev repo and is 26 lines. The core of it:

The infra repo has its own file and runbooks. If a rule matters, it fits on one line.

What it's built from

The CLI does no process management, no orchestration and no health checking itself. It sets environment variables, calls those tools and reads their answers. No platform team required, which is good, because we don't have one.

Checklist

Run this against your own setup:

At previous companies I saw slow onboarding, "works on my machine" bugs and silent failures. Every item on this list fixes one of those for humans too. Agents just make you fix them now.

The quickest test: give a new hire only your README and a terminal, and no one to ask. That's what an agent gets.