These days I use agents that write code often. When I am trying to build a new feature, I first write a markdown spec, then point the agent at it and send it on its way.
There are a lot of tools and choices today in the agent space. I regularly use 3-4 different ones, and I expect that number to continue to vary.
When you send an agent off to write code, you need to wait. If you have more work to do, especially work that is unrelated to the current changes the agent is making, it would be nice to unblock that work as well.
Git worktree makes this possible
A git repository can support multiple working trees, allowing you to check out more than one branch at a time. — https://git-scm.com/docs/git-worktree
Let’s build a simple project#
Feel free to skip to the Worktrees section if you already have a project you want to work on or come up with your own example.
If we go from zero, let’s set up a new git repo and make a commit.
mkdir -p our-project-with-worktrees
cd our-project-with-worktrees
git init
echo "Hello, world\!" > README.md
git add README.md
git commit -m "initial commit"
Now, let’s set up a simple fastapi
web server which will be the base of the two tasks we send the agents off to do.
Gemini was a little lazy here and didn’t create the virtualenv itself. Instead, it just wanted to install the dependencies to the system Python.
So we did this part ourselves:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Also, we add a .gitignore
for a Python project with the very convenient
npx gitignore python
We run the project with
uvicorn main:app --reload
and validate it works as expected
curl http://localhost:8000
{"message":"Hello, world!"}%
Cool.
Now one more modification to make our task a little more interesting.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root(name: str = "world"):
return {"message": f"Hello, {name}!"}
And let’s commit the results.
git add -A
git commit -m "Simple server"
The task#
We’re going to ask an agent to write a CLI to call the web server, supporting arguments, the input parameters, and dealing with the different HTTP methods for us.
This is a pretty contrived and even ill-defined task.
In my head, a successful outcome could be something like a hybrid between rails routes
and curl
.
But also, I’m not too worried about the outcome.
I just needed an excuse to use a worktree.
Write a generic CLI that can call the web server. The CLI should inspect the server route and input args to determine the inputs and flags to call the server. It should automatically extend to future routes added with no additional modification required, supporting optional and required arguments and enforcing type constraints. For example, based on the existing main.py, the CLI should support
python cli.py root --name=Alice
which outputs
{"message":"Hello, Alice!"}
and
python cli.py / --name=Bob
which outputs
{"message":"Hello, Bob!"}
Let’s see what the agent comes up with.
Worktrees#
Let’s create a new worktree.
git worktree add ../claude-code-1
cd ../claude-code-1
We’ve just created a new folder at the same level as our original project.
Now let’s send claude-code
off to work with the prompt above.
These days, I paste my prompts or specs into a specs
folder, then prompt the agent with something like “Implement @specs/cli.md”
I’ve been meaning to try OpenAI’s Codex, so let’s create another worktree and send it off on the same task.
git worktree add ../openai-codex
cd ../openai-codex
OpenAI sent me a email because they noticed I hadn’t tried the gpt-4.1
model.
I’m not sure I want to reward that behavior and give them a conversion, mostly because it just means I’ll get more emails but I digress.
I launched codex
and set it on its way
codex -m gpt-4.1
I sent it the same prompt as claude-code
, referencing the spec file I wrote.
codex
and gpt-4.1
seemed to have a pretty hard time with this ask.
The agent spent most of its time checking dependency installation, trying to run the web server, and looking around the project.
I started over, ensuring I had the dependencies installed and the virtualenv activated.
This second attempt, I tried with o4-mini
.
It felt noticeably slower than gpt-4.1
, but it did eventually write the CLI.
For both models with codex
, it was kind of hard to understand what the agent was intending to accomplish.
codex
prompts you to approve the commands it runs at each step but doesn’t provide much context on why it wants to run them.
You can read them to ensure they are safe, but it’s hard to assess whether the agent is on the right path – something that in my experience is pretty critical to getting good results.
Finishing up with the worktree#
I decided I liked what claude-code
built better, so now let’s commit in the worktree.
git add -A
git commit -m "Implement generic CLI to add endpoints"
and now let’s get the changes back into the main branch.
First, we go to the main branch in the original project folder. Clarify we’re in the right spot by running
❯ git branch
+ claude-code
* main
+ openai-codex
Now, we can merge the changes from the worktree.
git merge claude-code
and finally we can delete the worktree.
From the project folder:
git worktree remove claude-code
and cleanup the branch as well
git branch -d claude-code
Takeaways#
Git worktrees provide a straightforward primitive to working on multiple independent tasks within a project at the same time using agents. I don’t feel like my work here actually benefitted from using worktrees mostly because the agents didn’t actually take that much time to write the code relative to me figuring out how to make worktrees. That said, with a larger task or test suite that I could point the agent at as a goal, I could see worktrees being highly useful for longer agent runs, if you set up and task scope allow for it.