AI Engineer Code 2025
Hacking Subagents Into Codex CLI — Brian John, BetterUp
Read the talk
Hacking Subagents into Codex CLI
Brian John builds a small wrapper around child Codex processes to preserve delegation workflows, isolate context, and reuse approvals without disabling the sandbox.
From a talk by Brian John
Before you start: Familiarity with command-line coding agents, subprocesses, filesystem permissions, and basic Python will help you follow the implementation.
How do you take your subagent workflow with you?
How do you move between coding tools without giving up the delegation workflow that makes them useful? Brian John approaches that problem as a principal full stack engineer responsible for AI enablement in BetterUp’s R&D organization: helping people work faster and produce higher-quality results. At the time of the talk, he had spent more than eight years at BetterUp, which he describes as using AI from its beginning. Its mission—helping people live with purpose, clarity, and passion—also frames his invitation to engineers interested in working with LLMs.
Claude Code is his daily driver, and subagents are a regular part of his work. But those workflows create a dependency: switching tools can mean losing the ability to delegate in the same way. Codex CLI’s models look appealing to him, and he wants to use them without being locked into either one tool or one model family.
The main benefit is context isolation. The parent gives a subagent a problem; the child spends its own tokens investigating it and returns only the answer. The intermediate work does not fill the parent’s context window. John credits Dex Horthy’s context-engineering talk with changing how he works, particularly in large codebases. Delegation is therefore more than assigning a role: it controls how much working material the main agent has to carry forward.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A subagent is another Codex process
The implementation starts with a small observation: a subagent can be another instance of the main agent. There is no need to build a separate agent runtime. The parent Codex session can invoke a wrapper that starts a child through codex exec.
The complete execution loop has four steps:
- The parent calls the wrapper with a delegated task.
- The wrapper selects the agent definition, builds its prompt, and launches child Codex.
- The child performs the task and writes its final answer into a file.
- The wrapper reads that file and prints its contents to stdout, where the parent receives the result.
The answer file is the handoff between child and wrapper; stdout is the handoff between wrapper and parent. The design is small, but John’s first attempts immediately run into sandbox errors.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Getting nested permissions right
John does not solve those errors by disabling permission checks. The hard part is finding the minimum permissions that let the nested process work. In his setup, the parent needs at least --sandbox workspace-write to run the Codex command. The child then encounters another boundary: the OpenAI credentials in the user’s home directory sit outside the workspace accessible under the parent’s sandbox.
| Component | Requirement in the demonstration | Purpose |
|---|---|---|
| Parent Codex | --sandbox workspace-write | Permit the demonstrated child-launch workflow |
| Child Codex | --sandbox workspace-write | Write the answer file |
| Credentials | An accessible workspace location | Avoid depending on blocked home-directory access |
| Rollout recorder | Disabled | Avoid logging writes outside the workspace |
The child’s own settings cannot make the parent’s filesystem restrictions disappear. John therefore also disables the rollout recorder, the logging mechanism whose filesystem access causes trouble inside the enclosing sandbox.
Before proceeding, he evaluates the arrangement using Meta’s Agents Rule of Two. The framework examines three properties: processing untrusted input, accessing sensitive systems or private data, and changing state or communicating externally. Its security boundary depends on restricting at least one of these properties; allowing all three together calls for supervision.
John assumes his particular workflow does not process untrusted input. It does access private data through a proprietary codebase, and it can both change state and communicate externally. He considers the state changes in his environment relatively low risk and says the external communication is limited to OpenAI’s API endpoint. That is a conditional assessment of his system: lower risk does not mean no risk, and a different input source or set of accessible systems changes the assessment.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Teaching the parent how to delegate
A working wrapper is not enough: the parent needs to know it exists. The repository’s invocation instructions in AGENTS.md supply three parts of the contract:
- How: map a request for a named subagent to the wrapper invocation.
- When: delegate when the user asks, or when the parent judges delegation useful.
- What: list the available subagents and their responsibilities.
This turns a natural-language request to use a subagent into a concrete action the parent can perform.
John then opens the small BetterUp Codex CLI Subagent Demo. Its agent definitions contain a name, a reasoning-effort setting, and a prompt, much like Claude Code’s subagent definitions. He describes choosing lighter, medium, or higher reasoning according to the work. The two toy agents make that distinction easy to see: one counts words, while the other writes supplied text to a file, a task that needs little reasoning.
John describes the command wrapper as 72 lines. It accepts the inputs, calls the Python AgentExecutor, and prints the returned answer to stdout. The executor owns the process details: child permissions, reasoning effort, and rollout-recorder settings. Keeping those details together leaves the outer command focused on input and output.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Change the input files, keep the command
The invocation contract has an unusual detail: the parent writes the agent name into agent.txt and the user’s query into query.txt before running the wrapper. Passing both values as command-line arguments would be more obvious, but it would change the command on every request.
In the permission system John demonstrates, an exactly unchanged command can retain approval, while changing its arguments prompts for approval again. Moving variable data into files lets different tasks use the same invocation. The following Python example prepares a word-count request through that file interface:
python
from pathlib import Path
import subprocess
Path("agent.txt").write_text("word-counter\n", encoding="utf-8")
Path("query.txt").write_text(
"Count the words in this text: Small wrappers preserve useful workflows.\n",
encoding="utf-8",
)
subprocess.run(
["timeout", "600", "bin/agent-exec"],
check=True,
)
The sentence can change without changing timeout 600 bin/agent-exec. This separates the command being approved from the task data it will read.
The reusable approval is consequently approval to invoke the wrapper with changing file contents, not approval of one immutable query. Bypassing permission checks would remove the repeated prompts too, but that is not the operating mode John chooses.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Preparing a Codex home inside the workspace
A second wrapper prepares the parent session. It copies Codex home files from the user’s home directory into a workspace subdirectory so the nested process can access them. John describes this as syncing the files, pointing CODEX_HOME at the new location, and launching Codex. In the inspected repository, those responsibilities are split: bin/codex copies the files into tmp/codex-home, while AgentExecutor sets CODEX_HOME for the child. The accessible copy resolves the earlier credential-location problem.
The launch shown uses --full-auto. John associates it with workspace-write permissions but does not recall its precise approval policy. These flags and approval behaviors belong to the historical demonstration: the current CLI reference marks --full-auto deprecated, and current Codex supports native parallel subagents. The wrapper walkthrough explains how this setup worked without treating its historical limitations as current requirements.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
From the first approval to a verified file
With the prepared session running, John asks Codex to use the word-counter subagent. The parent recognizes that it needs the agent-execution wrapper, writes the agent name and query into their files, and requests permission to run the command. John chooses the option to approve it without asking again for that command. This first invocation establishes the approval that the next task will reuse.
The demonstrated workflow runs serially: the parent waits while the child does its work. John finds it slower than his Claude Code workflow and interprets Codex as better suited to hands-off, unattended work, while Claude Code feels more iterative to him. He accepts that tradeoff for his usage. The child’s result then appears on stdout, and the parent turns it into the answer shown to the user.
The second request uses the file-writer subagent. Codex writes a new agent name and query into the same input files and invokes the same command. This time there is no permission prompt. The task has changed, but the approved command has not.
The command uses timeout 600, giving the outer invocation ten minutes. John reports that large-codebase tasks can take ten minutes and sometimes as long as twenty minutes. That motivates allowing more time for substantial repository work. There is also an implementation detail to account for: AgentExecutor passes its own 600-second timeout to subprocess.run, so increasing only the outer timeout would leave the internal limit in place.
John reports that the easy file-writing example took about 40 seconds. These durations are observations from his usage and demonstration, rather than controlled comparisons across models or repositories. He finishes by checking that the requested file was written—the concrete output matters beyond the parent’s success message.
The recording closes with pointers to the open-source code and BetterUp, plus email and X direct messages for questions. The proof of concept ends at a useful boundary: two different delegated tasks, one reusable wrapper approval, and a file checked after creation.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
BetterUp's proof of concept with word-counter and file-writer agents, Python execution code, and launch scripts.
Meta's framework for limiting combinations of untrusted input, sensitive access, and external actions in autonomous agents.
Further reading
Dex Horthy explains context isolation, intentional compaction, and research, planning, and implementation workflows.
Updates since the talk
Current documentation for parallel subagents, custom agent configuration, and orchestration in Codex.
Read the complete timestamped transcript
- 0:02
Hi, everybody. My name is Brian John, and I'm excited today to talk to you about hacking subagents into Codex CLI. So who am I?
- 0:12
I'm a principal full stack engineer. My current focus at work is AI enablement for R&D, so think helping our R&D team members get their work done faster and with higher quality using AI.
- 0:25
The company I work for is BetterUp. It's an awesome place to work. We've been using AI since the very beginning. I've been there for over eight years now, which is longer than any place I've ever worked before.
- 0:36
And our mission is to help people everywhere live their lives with better purpose, clarity, and passion. If that sounds interesting to you, and you work on-- wanna work on cool stuff with LLMs,
- 0:47
please hit me up. I'll have my contact info in the last slide.
- 0:52
So why would we wanna hack subagents into Codex CLI?
- 0:59
Well, I've been using Claude Code as my daily driver since the very beginning.
- 1:04
It's a great tool. It's got tons of bells and whistles. It's got great models,
- 1:10
and I use subagents all the time. But I don't wanna be locked into one tool, and I really don't wanna be locked into one model family.
- 1:19
I wanted to be able to use other tools, particularly Codex CLI, because the models look really good,
- 1:27
and I wanna be able to still use subagents with them so that I can use my workflows with other tools.
- 1:35
Context management. So as you all know, subagents are amazing for context management. The main agent can give a problem to a subagent. It can go off, do its work, use its tokens, and pass just the answer back to the main agent.
- 1:51
And all that context that got used up by the subagent doesn't end up in your main context window, which is incredible. [chuckles]
- 2:01
And I don't think I have to say any more about this one. We've all seen this way too many times, and it gets annoying. And I have to give credit where credit is due.
- 2:09
This talk by Dex Horthy changed the way that I work with AI.
- 2:16
The workflows he proposes here I found to be really effective, especially in working with large code bases. I'd recommend you check out this talk. He's also talking at AI Engineer Code this year, and I recommend you check out that one too, `cause I'm sure it's gonna be great.
- 2:36
All right. So let's talk about design. At the end of the day, a subagent is really simple. It's just another instance of the main agent. So our design can also be really simple.
- 2:49
In this case, we're gonna have our parent Codex session. We're gonna have it run a script. It's just gonna be a wrapper script that's gonna kinda take care of, like, figuring out what agent to run.
- 3:00
It's gonna build the prompt, et cetera. And it's gonna kick off Codex Exec, so that child Codex is gonna run as the subagent. It's gonna respond to the prompt.
- 3:09
It's gonna do its work, and it's gonna write its answer into a file. And then our wrapper script is gonna read that file, and it's gonna print that result to standard out and give it back to the parent Cod- Codex session.
- 3:22
Pretty straightforward. Well, this is simple, so it should be easy, right? Well, that's what I thought too. And I started to get all these errors from Codex when I tried it.
- 3:36
Codex's sandbox really seems to not wanna let you do this. Now, you can of course run it with dangerously skip permissions or whatever. I don't do that.
- 3:47
But to get it to work with a normal set of permissions actually was really, really hard, and I banged my head against the wall a long time trying to get this to work.
- 3:59
So figuring out the minimum required permissions is probably the hardest part about this, getting the combination just right. On the parent, you need at least sandbox or workspace write to be able to run the Codex command.
- 4:12
You can always run that dangerously whatever, whatever command if you want. Again, I don't really do that. The child process is a little bit trickier. The sandbox prevents its access to the OpenAI credentials in your home directory since it's outside of the workspace.
- 4:30
The... You need at least sandbox workspace write again so that it can write the file that the, uh, wrapper script is gonna read. And you need to, to disable this thing called the rollout recorder,
- 4:44
which is like a logging thing. The-- Just because the parent sandbox, again, it prevents file system access to any subcommands that are outside of the workspace.
- 5:00
All right. Before we go any further, I have to give a quick note about security.
- 5:06
Meta recently wrote a great paper called "The Agent's Rule of Two" that I think explains this really, really well. And what it says is there's three things you need to care about with your agent when it comes to security:
- 5:17
whether it's processing untrustworthy input, whether it has access to sensitive systems or private data, and whether it can change state or communicate externally.
- 5:27
In our case, we're not processing untrustworthy inputs. We do have access to sensitive systems or private data because we're probably working with a proprietary code base.
- 5:39
And it can change state, and it also can, can communicate externally. Now, the state that it can change is really kinda dependent on your system. In my case, it's really not very high risk, and the communication it does externally is just to OpenAI's API endpoint.
- 5:56
So again, not a major risk, I would say, so that puts us in the lower risk category. But importantly, lower risk does not mean no risk. So your mileage may vary here You need to make your own determination on if this is something you feel comfortable with.
- 6:14
And with that, let's move forward. All right, so to get Codex to be able to use subagents with this wrapper script and everything, we have to tell it how to run them.
- 6:26
So in our agents.md, we're gonna have just a little bit of information here that tells Codex, "Hey, when I say use the whatever subagent, go and actually, like, run this script and, you know, with these commands or whatever," and that's how you do it.
- 6:47
Also, we have to tell it when to run subagents. So that would be, you know, when the user asks or just when you think it'd be helpful. And then we wanna tell it what subagents are available and what they do.
- 7:04
All right. With that, let's do a quick demo.
- 7:10
I've put together a really quick and small proof of concept repository. It's open source, so you can go and take a look at it yourself. I'll have the URL at the end of the talk.
- 7:21
Let's just take a look at what's in here.
- 7:24
So first of all, let's take a look at our agents.
- 7:28
I just created a couple of toy agents here. Let's go take a look at them. They're defined.
- 7:35
You can see here each agent has a name. It also has a reasoning effort. So depending on what kind of work it's doing, you can give it a light, medium, you can give it a high reasoning effort, whatever you think is appropriate.
- 7:49
Then you just give it, you know, the prompt for the agent, so very similar to kinda how Claude Code subagents work. In this case, it's just counting words. You know, this other one is a file writer agent.
- 8:00
Just gonna take some text and put it in a file. Don't need much reasoning for that.
- 8:07
All right. So now let's look at our wrapper script.
- 8:15
It's really small, only 72 lines. Basically just takes in the inputs.
- 8:24
It's gonna call this AgentExecutor Python class, which I'll show in just a minute, also very small, and it's gonna return that, uh,
- 8:33
the agent's output to standard out so that the main agent can see it. Let's look at that AgentExecutor class.
- 8:42
Not gonna go through this whole thing. Again, it's pretty small. Basically just kicks off the child subagent with the proper permissions and with the right reasoning effort,
- 8:53
and it disables the rollout recorder, all that kind of stuff. Just does all that for you, so pretty handy. One thing that I think I didn't cover, if you look at agents.md,
- 9:05
is, it's kind of important here, is this part. So when we're telling Codex how to invoke the subagent, we're gonna have it write the agent name to a file, we're gonna have it write the user's query to a file, and then we're gonna have it run this command.
- 9:22
You know, another alternative to this would be to actually pass the agent name and the query as command arguments. The reason why we don't wanna do that is because of Codex's permissioning system.
- 9:36
As long as the command looks exactly the same,
- 9:39
you only have to grant permission once. But if you have different arguments to the command, you have to approve it every time.
- 9:48
So it gets really annoying if you have to approve every time the C- Codex wants to call a subagent.
- 9:57
So in this case, we make the command look exactly the same. Codex is just gonna run it.
- 10:03
Now, if you run, again, with dangerously skip permissions or whatever, you don't have to worry about this.
- 10:09
But all right, let's go in. Oh, then we've got this also is wrapper script around Codex, so let's take a look at that real quick. Super simple. Uh, what it does is it takes the Codex home files from your home directory, it's gonna sync them into a subdirectory so it has access to them, and it's gonna set
- 10:25
CODEX_HOME to that directory, then it's just gonna launch Codex. In this case, I'm launching it in full auto mode, which is just, like, shorthand for workspace-write plus, I think, approval on a request or something like that.
- 10:37
I can't remember which one. Um, but pretty straightforward. Not much going on here. Really not much code.
- 10:45
All right, let's go ahead and launch this.
- 10:50
Okay. Now let's just give it just a quick
- 10:55
query. I'm gonna tell it to use its word counter subagent,
- 10:59
have it go off and do that. You're gonna see it
- 11:06
figure out that it needs to run this AgentExec. It's gonna go ahead and put the name of the agent in a file, it's gonna put the query in a file, then it's gonna ask me for permissions to run it, and it's really important here that I say yes and don't ask again for this command.
- 11:20
That way, it's not gonna ask me every time it has to run a subagent.
- 11:26
You'll notice that it's running everything in serial here. Codex does not have the ability to run things asynchronously like Claude does, so this is slower. And Codex in general, if you've used it, I think you'd find it's slower overall than Ch- than Claude Code, but I think that's really kind of intentional.
- 11:47
Seems like Codex is really kind of meant to be more of, like, a hands-off unattended type of a tool versus Claude Code is meant to be more kind of iterative.
- 11:56
And so, you know, I think that's actually okay. I found this okay for me the way that I've used Codex. All right. So we can see we got that result back, printed to standard out here, and then
- 12:09
Codex just gave us back the answer. So let's just do one more with this file writer subagent.
- 12:18
Again, it's gonna do the same thing. It's gonna write that agent name into a file. It's gonna write the query into a file. Then it's gonna call that same command.
- 12:29
It will not ask for permissions this time.
- 12:34
Oh, and we're using the timeout 600 here because some of these agents can actually take a long time to run. If you're having to do a big task that's gonna have it look across a whole code base and you have a large code base, it can take up to 10 minutes.
- 12:48
I've actually seen them take longer, up to 20 minutes sometimes, so you might even want a longer timeout here. This is what I've set for this example. In this case, this is a pretty easy one, so it only took about 40 seconds.
- 13:01
All right, so it wrote the file. Just go ahead and verify that.
- 13:06
All right. All right. That's all I have. The-- You can find the code at that URL.
- 13:14
You can find BetterUp at betterup.com. If you have any questions for me, you can use my email address, or you can DM me on X. I don't post anything on X, so really no reason to follow me, but go ahead if you want.
- 13:28
And I hope this was helpful for you. And again, if BetterUp sounds like an interesting place to you, please hit me up. Have a great day.