Worktrees and environments

How two agents work in one repo at once, what AgentCron provisions (nothing) and what it brokers (the namespace).

The problem

Two agents in one checkout is a merge conflict. Two agents that both start the app to check their work both want port 3000 and both want the database called app_dev.

Neither of those is a hard problem individually. Together they are the reason people run one agent at a time.

Worktrees

Agents work in their own git worktree rather than your main checkout, so two of them can hold different branches of the same repo at the same time without seeing each other's edits. Your working copy stays yours — you never come back to a dirty tree you did not make.

The agent creates the worktree, as part of its own work. AgentCron does not create one per run. What it does is provision the environment inside one the first time that worktree is used, which is the part an agent cannot do for itself because it requires knowing what every other worktree is already using.

Environments

Where your project defines a setup script, each worktree gets:

  • A sticky, collision-checked block of ports. Sticky means the same worktree gets the same ports every time, so a URL you bookmarked keeps working. Collision-checked means it is verified against a ledger of what is already allocated, with accounting for leaks.
  • Its own database name.
  • Its own compose project name, so containers do not collide either.

These are handed to the agent as environment variables it is told to read rather than assume. That instruction is in the injected preamble, and it is the difference between an agent that connects to its own database and one that quietly writes into the app you left running.

Then your repo's own setup script runs.

What AgentCron provisions: nothing

This is deliberate and worth understanding before you evaluate it.

AgentCron computes a collision-free namespace and runs your script. It does not know whether you need Postgres or MySQL, whether your migrations are idempotent, or whether your seed data takes four seconds or four minutes. Anything that tried to would be wrong for most projects and impossible to debug when it was.

The cost of that decision is a real onboarding cliff: if your project does not already have a script that can bring up a fresh instance of itself, you write one on day one. Two example templates ship, and both are Postgres-shaped. A MySQL, Mongo or Redis project starts from a blank file.

The benefit is that once it exists, it is your script, in your repo, and it works the same whether an agent runs it or you do.

Without a setup script

Everything still works — agents still get separate worktrees, and the review, log and gates are unaffected. They just share the machine's ports the way they would have anyway, which is fine right up until two of them need to run the app at once.

The isolated-environment instructions are only added to a prompt when your project actually defines the contract, so a project without one does not pay tokens for rules it cannot use.

Servers agents leave running

An agent that starts a dev server to check its work registers it with its port, pid and log file. Liveness is confirmed by checking that the port actually listens, rather than by trusting a pid.

An unregistered background process is invisible the moment the agent exits. This is the difference between a clean machine in the morning and eleven orphaned node processes you find on Thursday.

Cleanup

Worktrees accumulate, and they are the largest thing on disk by a wide margin — the machine this was built on carries over a hundred of them.

The storage view shows where the disk went, per category. Cleanup previews what it would free and only deletes when you confirm. Removing a checkout is deliberately not something cleanup does and not something an agent can do — deleting a worktree that still holds unreviewed work is the one mistake here that loses real output, so it stays a decision you make in Settings.