Skip to content
Go back

Three Codex Threads, Three Command Names: Keeping Parallel Agents From Talking Over Each Other đź§µ

Three terminals open. Three jobs running. One brain trying to hold all of them.

That was the shape of a perfectly ordinary day in August, and the only reason it didn’t end in a mess of half-applied diffs is that I’d finally stopped treating codex as one command. It’s three. And which of the three you type decides what that thread is allowed to do next.


The Three Names 🏷️

For a long time I assumed the subcommand was cosmetic. Interactive or not — same engine underneath, right?

No. Each of these opens a genuinely different kind of session:

CommandWhat startsWhere it goes afterwards
codexThe interactive TUIStays attached. I drive it turn by turn.
codex execA non-interactive runDoes the job and gets out of the way.
codex resumeA saved sessionReattaches to an existing thread with its history intact.

Same binary — codex-cli 0.154.0 on this machine — but three different relationships with my attention:

That third row is the one that changed how I work.


Naming Is The Whole Trick đź“›

Here’s the part I’d underline if I could only keep one sentence of this post:

Parallel threads are only safe if you can tell them apart without reading their output.

codex resume --last is a footgun the moment more than one thread exists — “the most recent” is a race condition, and I have lost work to that exact assumption. So the rule became: if a thread is going to outlive the terminal that started it, it gets a name at birth.

Three threads, three names, three jobs:

codex                       → the thread I'm driving by hand
codex exec                  → the thread doing something boring and long
codex resume <name>         → the thread I keep coming back to

And because codex archive and codex delete both take a name as readily as an id, tidying up doesn’t mean hunting through UUIDs either:

$ codex archive billing-refactor
$ codex delete scratch-prompt-test

The name is the interface. The UUID is just an implementation detail I shouldn’t have to look at.


The Three Threads, Side By Side đź§¶

Diagram: three Codex entry commands side by side. `codex` starts an interactive TUI thread, `codex exec` starts a non-interactive one-shot run, and `codex resume` reattaches to a named saved session. All three feed into a shared local daemon that holds the session history, and only the interactive and resumed threads can queue follow-up messages.

The arrow that matters is the one at the bottom. Sessions live on a shared local daemon, which is why codex agents can browse all of them from one place regardless of which command opened each. That’s the feature that makes three threads a workflow instead of three unrelated windows I have to remember the state of.

$ codex agents

One list. Every thread. No guessing which terminal held which half of the job.


What Each Thread Is Allowed To Touch âś‹

Naming them turns out to be only half the discipline. The other half is deciding — before they start — which one is permitted to change files.

The split I’ve settled on:

  1. The thread I’m driving gets the working tree. It’s the only one with my full attention, so it’s the only one that should be moving code underneath me.
  2. The one-shot thread gets read-only work: reviews, explanations, “what would break if…” questions. codex exec review is built for exactly this and doesn’t need write access to answer well.
  3. The returning thread gets a branch of its own, and never the one I’m sitting on.

Two threads writing to one working tree is not parallelism. It’s two authors with one pen.

And when a thread finishes and its diff is worth keeping, there’s a command for that too — codex apply hands the most recent diff to git apply on my working tree, rather than me copy-pasting output between windows like it’s 2019.


The Check I Run When Something Smells Off đź”§

The one command I’d memorise alongside the three above:

$ codex doctor

It diagnoses the local installation, the config, the auth and the runtime health. When three threads are misbehaving at once, the boring answer is almost always one of those four — and I’d much rather be told that in ten seconds than discover it in the middle of a rebase.

Config itself lives in ~/.codex/config.toml, and any single run can override a key without editing the file:

$ codex exec -c model="..." "explain the failing test"

Which means a thread can be configured differently from its siblings without any of them knowing about it. Useful. Also, the reason naming matters — otherwise I have no way of remembering which one I pointed at what.


What Three Threads Actually Buys Me 🎯

Not speed, mostly. Continuity.

The failure mode of one long thread isn’t that it’s slow — it’s that it accumulates. Every exchange makes the next one heavier, and eventually I’m paying to re-explain context I already settled twenty messages ago.

Three short threads with names beat one very long one for the same reason three small branches beat a six-month-old megabranch: you can drop one without losing the rest.

So: codex when I need a conversation, codex exec when I need an answer and then silence, codex resume when the conversation was worth continuing. Three names, three jobs, one daemon holding all of it.

That’s the whole setup. It took me embarrassingly long to notice the subcommand was the point. 🧵

Do you run agents in parallel, or does the context-switching cost eat the gains? I’d genuinely like to know where the line is for other people. 👇


Share this post on:

Previous Post
Three AIs Score, Write And Review My Applications — Only I Get To Send Them 🚀
Next Post
Sending A Squad After One Bug: One Hypothesis Per Agent 🔦