# Codex remote environments

> Point the Codex CLI at a Prized box: Codex works on the box with your laptop closed and your terminal attaches with codex --remote, or your laptop's Codex runs every command on the box through an exec-server environment.

URL: https://prized.dev/docs/codex-remote-environments
Updated: 2026-11-05

The Codex CLI can work away from the terminal you type in, in two ways. Both reach the box over SSH by its name (`fig` here; yours are in `prized box ls`), which `prized setup` adds to `~/.ssh/config`, so nothing on the box listens on a public port. Both use parts of Codex that OpenAI marks experimental; this page was checked with Codex 0.166.0.

|  | Codex on the box (`--remote`) | Laptop Codex, box commands (exec-server) |
| --- | --- | --- |
| Where the agent runs | the box | your laptop |
| Laptop closed or asleep | keeps working until it needs an approval or the box pauses; attach again later | stops, and so do its commands on the box |
| Codex sign-in | on the box | your laptop's |
| Project folder | the box's copy, `~/code/myproject` | the same path on both machines |

For agents that keep working with the lid closed, use the first. The ChatGPT desktop app has its own SSH connection to a box: [Codex remote](https://prized.dev/docs/codex).

## 1. Sign Codex in on the box [#1-sign-codex-in-on-the-box]

In your project folder:

```bash
prized setup --sync --agent codex
```

This syncs the folder to `~/code/myproject` on the box and signs Codex in there with a sign-in of its own ([Run Codex in the cloud](https://prized.dev/docs/run-codex-in-the-cloud#2-a-chatgpt-sign-in-of-the-boxs-own)).

## 2. Add `codex-box` to your shell [#2-add-codex-box-to-your-shell]

Paste this into `~/.zshrc` or `~/.bashrc`, then open a new terminal:

```bash
codex-box() {
  local box=${1:?usage: codex-box BOX [resume --last | agents]} dir out sock; shift
  dir=${CODEX_BOX_DIR:-code/$(printf %s "${PWD##*/}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9._' - | sed 's/^[._-]*//; s/-*$//')}
  out=$(ssh "$box" "bash -lc 'codex app-server daemon start >/dev/null 2>&1 || exit 3; cd ~/$dir || exit 4; echo \$HOME \$PWD'") || { echo "codex-box: Codex did not start on $box, or ~/$dir is not there" >&2; return 1; }
  sock="$HOME/.codex/prized-$box.sock"
  pkill -f "L $sock:" 2>/dev/null
  ssh -fN -o ExitOnForwardFailure=yes -o StreamLocalBindUnlink=yes -L "$sock:${out%% *}/.codex/app-server-control/app-server-control.sock" "$box" || return
  codex "$@" --remote "unix://$sock" -C "${out#* }"
}
```

It starts Codex's background server on the box, forwards its socket over SSH to `~/.codex/prized-BOX.sock`, and opens the Codex terminal UI in the box's copy of the folder you are in. `CODEX_BOX_DIR=code/other codex-box fig` picks another folder under the box's home.

## 3. Give Codex a task, then close the lid [#3-give-codex-a-task-then-close-the-lid]

```bash
cd ~/code/myproject
codex-box fig
```

The task runs in the background server on the box. Leave with `/quit`, close the terminal or close the laptop, and it keeps working; Ctrl+C while Codex works interrupts the turn instead.

* **Approvals wait for you.** A turn that asks for approval waits until you attach, so set the sandbox and approvals before you leave ([Run Codex in the cloud](https://prized.dev/docs/run-codex-in-the-cloud#3-sandbox-and-approvals-before-you-leave-it)).
* **Auto-pause.** Codex's background server has no terminal on the box, so it counts as use only through sustained CPU or network traffic. Before a long run, `prized box auto-pause fig off`, and switch it back after ([Auto-pause](https://prized.dev/docs/boxes#auto-pause)).

## 4. Attach again [#4-attach-again]

From the same folder:

```bash
codex-box fig resume --last
```

This opens the last conversation in that folder, finished or still streaming. `codex-box fig agents` lists the chats on the box, including ones started in a `prized ssh` session.

## Laptop Codex, commands on the box [#laptop-codex-commands-on-the-box]

Codex reads remote environments from `~/.codex/environments.toml`. With this file, every new Codex session on your laptop runs its commands and file edits on the box:

```toml title="~/.codex/environments.toml"
default = "fig"

[[environments]]
id = "fig"
program = "ssh"
args = ["fig", "bash", "-lc", "'exec codex exec-server --listen stdio'"]
```

Codex sends the path of the folder you started it in, so that path has to exist on the box. From your project folder, link the synced copy to the same path there:

```bash
name=$(printf %s "${PWD##*/}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9._' - | sed 's/^[._-]*//; s/-*$//')
ssh fig "sudo mkdir -p '$(dirname "$(pwd -P)")' && sudo ln -sfn ~/code/$name '$(pwd -P)'"
```

* **It stops with the laptop.** The agent runs on your laptop: when Codex quits, the box ends the commands it started, and when the laptop sleeps they end once its SSH connection drops.
* **Back to local.** Delete the file, or set `default = "local"`, then start Codex again.

## Troubleshooting [#troubleshooting]

| Symptom | Fix |
| --- | --- |
| `exec-server rejected request (-32603): No such file or directory` | The folder's path does not exist on the box; link it as above. |
| `codex-box: Codex did not start on fig, or ~/code/myproject is not there` | Run `prized setup --sync --agent codex` in the folder first, or set `CODEX_BOX_DIR`. |
| SSH says the box is paused | Run `prized box resume fig`, then run your command again. A turn that was running when the box paused does not continue; `codex-box fig resume --last` reopens the conversation. |
| `codex-box` cannot connect after the laptop slept | Run `codex-box fig resume --last` again; it replaces the old forward. |
| A prompt asks to trust the folder | Answer it; Codex asks once per folder on the box. |
