Opens in a new tab
Explainer

Running Codex CLI as a supervised worker process

In brief

A host restarts while its Codex worker may still be editing. Follow the saved process, events and patch to resume the job without starting a second writer.

6 min read

Is this the right starting point?
Before you read
Practical application/process-supervision experience, including Git workspaces, child processes and failure recovery.
What you will take away
Design a Codex worker supervisor that records ownership, reconciles uncertain outcomes and verifies artifacts after cancellation or restart.
Sources
A compact worker capsule is connected to a parent controller by input, event and cancellation rails, with verified artifacts exiting to a tray.
On this page6 sections

An internal release tool starts a Codex worker to prepare a tested patch, then the host restarts. In this hypothetical case a patch may already exist and the worker may still be alive. Before starting again, the tool needs to find where the first attempt left the work.

Launching codex exec is only the beginning. The host owns the process afterward. Keeping task, events and workspace in one execution record lets it distinguish a timed-out wait from a worker that actually stopped.

A CAD Studio report illustrates the issue. The Mac app launches codex exec --json, turns JSONL events into chat steps and resumes a thread. Its author reports waiting, retrying and terminating child processes because resuming can fail while an earlier writer remains alive. That is one implementation's report, not a universal Codex guarantee.

Choose the integration layer before writing a supervisor

OpenAI documentation distinguishes exec for scripts and bounded jobs, the SDK for programmatic task control, and app-server for products needing persistent conversations, streaming, interruption, tools and approvals.

Choose the smallest layer that supports the behavior you must own. A one-shot check can be a child process returning structured output. Persistent users, approvals and interrupted conversations require more coordination; constructing that around shells may cost more than using the SDK or app-server.

Even a single worker has input, output, errors, a process, directory, thread and files. Record them together. After a restart, the surviving pieces let you reconstruct what happened.

A host application owns the execution ID, thread lease, deadline and permissions around a codex exec child process, then separately accepts its terminal event and artifacts.
Supervised worker lifecycle. A timeout or crash leaves an outcome to reconcile; it does not prove the workspace or external state is unchanged.

Treat JSONL as an event stream, not the result

Before our hypothetical host restarts, its worker reports a file change. That is useful progress: there may now be a patch worth keeping. It is not yet a tested patch. The next event might be a failing test, or a command might start without ever reporting a successful finish.

OpenAI's evaluation guidance describes these newline-delimited JSON events from codex exec --json, including commands and file changes. Each line records a step. Its example saves and parses the trace to check for required commands and artifacts. The host can use that sequence alongside the process exit, actual files and task-specific checks; even the final message remains the agent's account of the work.

Imagine reopening the release tool and seeing only “file changed” in its compact chat view. Did the worker stop there, or did the display leave out a later event? Saving raw events before simplifying them gives you somewhere to look. A renderer may hide repetition for readability without throwing away the original sequence. Keep secrets out at the source, and restrict trace access separately from artifact access: a person allowed to read the patch does not necessarily need everything the worker saw while making it.

One task needs one process owner

Assign an execution ID before launch. Record process and available thread IDs, directory, requested sandbox and approvals, start, deadline and expected output. Events may update a heartbeat. The host owns cancellation and cleanup because a vanished worker cannot reliably report itself.

Suppose host A loses its connection but its worker keeps editing. A’s ownership claim expires, and host B considers resuming the same thread. Expiry alone is not proof that A stopped. Before B launches, it must check the recorded process and workspace, then recover ownership only when the earlier writer has stopped or has been safely isolated. An atomic lease records one owner and an expiry; renewal keeps a live owner’s claim current. The supervisor must also enforce that claim, so an old worker cannot continue writing after a replacement takes over.

The skill execution guide asks the same practical questions after interrupted work: which changes are established, which might still be happening, and what is the worker allowed to do next? Saving that state lets host B resume a known task instead of hoping that another launch repairs the uncertainty.

If the host crashed after a file change, replay can overwrite useful work or repeat an external effect. Inspect Git state, artifacts and permitted destinations first. Classify completion, failure, continued running or unknown. The reconciliation guide explains why a lost response needs readback before another write.

Cancellation has more than one edge

Now let the same patch run reach its deadline while a command is still active. The timer tells the host to stop adding work and request interruption; it does not tell us that the worker has exited. A bounded grace period gives the host time to drain output, including a final event arriving just after the deadline. If the child remains, the host may need to terminate it and escalate, keeping the signals and observed exits in the record.

There can be another process behind that child. Suppose the worker's shell launched a test process before the interruption. Ending only the shell can leave that descendant running while a replacement worker starts changing the same files. Cancellation therefore needs the owned process group or the platform's equivalent, not a broad process name that could catch another user's session. The useful fact is which processes actually stopped, not that the stop button was pressed.

The patch can outlive both processes. Cancellation does not reverse a file change or an earlier external effect, so the host still has to decide whether to keep, revert or hold the artifacts. For code, that means inspecting the diff and untracked files and checking the build and tests, just as after normal completion. The CAD application needs its own model and geometry checks. An interrupted run can leave useful work; it can also leave unfinished work that looks surprisingly complete in the chat window.

Sandbox and approval settings are part of the record

The reported command selects workspace-write sandboxing and a host-chosen approval policy. Official guidance recommends the permissions needed for the task. Preserve those settings because they bound what the attempt could have done.

For example, a patch may need a dependency download that the selected network policy denies. Show that failed operation and let the host decide whether to provide the dependency, authorize a bounded download or leave the task unfinished. Silently giving the worker unrestricted network access would change what it can do beyond fixing this one failure.

A finished patch can wait safely for review. Publishing it, sending a message or deleting remote data creates effects outside the workspace, so the host needs explicit authorization and a record of the result for those actions. After a crash, that record helps answer whether to resume preparation or first check whether the external action already happened.

Verify the artifact and the supervisor

Replay the host crash just after the patch is written. On restart, can the release tool find that patch and determine whether the original worker is still editing it? Then try the neighboring failures: a deadline with a surviving descendant, malformed JSONL, a missing terminal event and two hosts attempting to resume together. Each test should leave the host with a bounded state and enough evidence to choose the next action, rather than another reason to launch blindly.

Finding the patch does not make it a good patch. Deterministic checks of the trace and artifacts can establish particular requirements; qualitative review is still needed where those rules cannot judge the work. A reliable supervisor can deliver bad work, and a capable agent can lose useful work through an unreliable host. Both deserve a test of their own.

After restart, the execution ID leads back to the worker, thread, directory and trace. A finished patch can move to verification, a surviving process needs its ownership reconciled, and uncertain partial work can stay on hold. The host can continue from what the first attempt actually left behind, without discarding it or doing it twice.

Sources & context

Sources linked in this article. Read alongside the author’s analysis; a citation does not independently verify a publisher’s claims.

Report an error or outdated detail

More on OpenAI

All OpenAI coverage

Keep reading

Where to go next