Systems · case study
grex
One workspace to run Claude, Codex, Cursor and Gemini agents in parallel — and keep their work from colliding. This is the study of its decisions, not a feature tour.
The problem
Coding agents arrived as separate terminal applications, each with its own habits, auth and output. Running several at once on one repository produces a different failure every day: two sessions overwrite the same file, one hangs, another finishes while you were watching the third. The problem is not intelligence — it is coordination.
The constraints
- 01
Vendor CLIs are interactive TUIs — there is no clean library to call.
- 02
Agents write to real repositories with the user's own credentials.
- 03
Sessions are long-running and can hang, crash or produce nothing.
- 04
It has to stay a desktop app — no server in the middle.
The decision map
- 01 Operator You, one window keyboard-first
- 02 Session orchestrator A supervisor for every run process per session D3
- 03 Vendor adapters A small bridge per agent claude · codex · cursor · gemini D2
- 04 Isolated worktrees Its own copy of the repo git worktrees D1
- 05 Event protocol Status without reading screens D4
- 06 Review & merge You decide what lands human in the loop
D1–D5 are explained below. Hover a node to find its decision.
The decisions
- D1
How agents stay out of each other's way
- Context
- Two agents editing the same repository in one working tree overwrite each other within minutes.
- Options
- Branches in a single working tree · full repository clones · git worktrees · containers
- Chosen
- Git worktrees — one directory per session, same history.
- Why
- Agents need the same repo and instant setup. Clones duplicate history and cost disk; branches share one working tree, which is exactly the collision we are trying to remove.
- The cost
- Branch hygiene becomes the user's job, and it is easy to forget a worktree exists.
- D2
How to talk to the vendor CLIs
- Context
- Claude, Codex, Cursor and Gemini ship as interactive terminals — not as tidy libraries.
- Options
- Vendor SDKs and APIs · scraping the terminal UI · wrapping the real CLI in a pseudo-terminal
- Chosen
- Wrap the real CLI in a PTY.
- Why
- The real CLI keeps the user's existing auth, plan and behavior. An API integration would fork behavior and bill separately — a different product wearing the same name.
- The cost
- Terminal output is a moving target. Parsing it is the most fragile part of the system.
- D3
How sessions run in parallel
- Context
- A hung or crashed agent must not take the whole workspace down with it.
- Options
- One multiplexed thread · thread per session · process per session with a supervisor
- Chosen
- Process per session, supervised.
- Why
- Process boundaries are the cheapest isolation available: a dead agent is one dead process, not a dead application.
- The cost
- Memory and startup cost per agent; the supervisor has to be written and tested like real infrastructure.
- D4
Where state comes from
- Context
- The workspace shows what every agent is doing — without depending on what the screen happens to say.
- Options
- Read vendor log files · parse terminal output · require adapters to emit explicit events
- Chosen
- A small event protocol, emitted by each adapter.
- Why
- Status should be a fact the system states, not a guess made from pixels. Events survive cosmetic CLI changes; screen scrapes do not.
- The cost
- Every vendor update can break an adapter, so adapters must stay boring and small.
- D5
Where the machine lives
- Context
- Agents read real repositories with real credentials.
- Options
- Cloud orchestration · a server you host · local-first desktop
- Chosen
- Local-first desktop. Nothing transits a server.
- Why
- The code and the keys never leave the machine, and the app works offline. This is a product decision as much as an engineering one.
- The cost
- No cross-device sync, and the machine's resources are the ceiling.
The trade-offs I accepted
- Wrapping real CLIs is inherently fragile. Every vendor update is a small risk, accepted in exchange for authentic behavior.
- Parallel agents consume real resources — CPU, memory, attention. Parallelism is a tool, not a default.
- Auto-merging results is out of scope by design. The human stays in the merge decision.
What failed
- Treating every vendor as the same adapter. Auth and update flows differ; the adapter interface had to become narrower and more honest.
- Reading terminal screens to detect status. It broke on cosmetic output changes, and was replaced by explicit events.
- Experimenting with applying agent results automatically. Reverted — the merge decision belongs to the person who owns the repo.
What I learned
- Adapters should be boring and small. Cleverness belongs in the orchestrator, where it can be tested once.
- Process isolation beats in-process cleverness: a failure should cost one session, not the workspace.
- When several agents work in parallel, the scarce resource is not tokens — it is the human's ability to review.