> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# サンドボックスで Codex を実行する

> サンドボックスで Codex CLI を実行するか、ローカルの CLI を接続するか、リモートprojectでデスクトップアプリやモバイルアプリを使用します。

CoreWeave サンドボックス内のリポジトリを対象に Codex を実行します。
サンドボックス内で Codex コマンドラインインターフェース (CLI) を実行する方法、ローカルの CLI を Codex app server に接続する方法、リモートprojectでデスクトップアプリやモバイルアプリを使用する方法の 3 つがあります。
いずれの方法でも、エージェントのプロセス、ワークスペース、コマンドの実行はすべてサンドボックス内で完結します。
これらの例では、モデルへのリクエストに OpenAI を使用します。

<h2 id="choose-how-to-run-codex-in-a-sandbox">
  サンドボックスで Codex を実行する方法を選択する
</h2>

app server は、リモート CLI およびデスクトップ接続のためのエージェントバックエンドです。
エージェントを操作する場所を選択してください。

| インターフェース | インターフェースの実行場所 | エージェントプロセスの実行場所 | 接続方法 |
| - | - | - | - |
| [サンドボックスで Codex CLI を実行する](#run-codex-cli-in-a-sandbox) | サンドボックス内 (ターミナルに表示) | サンドボックス内 | `cws-agent` でアタッチ |
| [ローカル CLI を Codex app server に接続する](#connect-your-local-cli-to-codex-app-server) | お使いのコンピューター上 | サンドボックス内 (Codex app server 経由) | `codex --remote` で接続 |
| [デスクトップアプリとモバイルアプリを使用する](#use-the-desktop-and-mobile-apps) | お使いのコンピューター上、またはそのコンピューターとペアリングしたスマートフォン上 | サンドボックス内 (Codex app server 経由) | デスクトップアプリで Secure Shell (SSH) projectを追加します。Remote でスマートフォンをペアリングします。 |

アタッチ型の CLI は `cws-agent` を使用してサンドボックスを作成します。ローカル CLI とデスクトップ
アプリは、共通の [SSH サンドボックスのセットアップ](#create-an-ssh-accessible-sandbox)を使用します。

モバイルからアクセスするには、Remote でスマートフォンをデスクトップホストとペアリングします。
スマートフォンはそのホストに接続し、ホストが SSH 経由でサンドボックスに接続します。デスクトップ
ホストはスリープさせず、オンラインの状態でアプリを起動したままにしてください。
[Remote を介したモバイルと別のデスクトップ](#mobile-and-another-desktop-through-remote)を参照してください。

ローカルのターミナルユーザーインターフェース (TUI) は、入力の送信、出力の表示、承認の処理を
担います。リモートのエージェントセッションは app server が管理します。ラップトップ上で実行されている
エージェントからコマンドを 1 つずつ転送する仕組みではありません。
[OpenAI app server ガイド](https://learn.chatgpt.com/docs/app-server)を参照してください。

app server を起動しても、そのセッションがデスクトップアプリやモバイルアプリに登録されるわけではありません。
これらのインターフェースでは、[デスクトップアプリとモバイルアプリを使用する](#use-the-desktop-and-mobile-apps)で
説明する別途の接続セットアップを使用します。OpenAI の
Remote ドキュメントでは、このセルフホストセッションに Web サイトからアタッチするフローは
示されていません。ブラウザーからのアクセスは本ガイドのスコープ外です。

プログラムから利用する Agents API ワークフローは、別の実行モデルを使用します。
[OpenAI Agents API レシピ](https://github.com/coreweave/cwsandbox-recipes/tree/main/recipes/openai-agents-api)を参照してください。

<h2 id="prerequisites">
  前提条件
</h2>

開始する前に、以下を準備してください。

* `SANDBOX_USER` action が付与された [CoreWeave API アクセストークン](/ja/products/sandboxes/placement#choose-and-get-credentials)。CPU サンドボックス用のキャパシティも必要です。
* Codex でサポートされている OpenAI アカウント、または OpenAI APIキー。このガイドの app server
  の例では、APIキー認証と API 請求を使用します。
* 公開リポジトリの URL。非公開リポジトリをクローンする場合は、サンドボックス内に Git の認証情報が必要です。
* OpenAI、パッケージレジストリ、および Git ホストへのアウトバウンド接続

ローカルのターミナルで `[API-ACCESS-TOKEN]` を CoreWeave API アクセストークンに置き換えてから、
サンドボックスの認証情報を読み込みます。

```bash theme={"system"}
export CWSANDBOX_API_KEY="[API-ACCESS-TOKEN]"
```

サンドボックス作成の例では、非アクティブ状態によるタイムアウトではなく、実時間で最大 8 時間の
有効期間を設定しています。作業が終了したらサンドボックスを停止してください。モデルの使用料と
サンドボックスのコンピュートには、それぞれ別に料金が発生する場合があります。

<h2 id="run-codex-cli-in-a-sandbox">
  サンドボックスで Codex CLI を実行する
</h2>

`cws-agent` を使用してサンドボックスを起動し、ターミナルをアタッチします。Codex TUI
とエージェントプロセスは、どちらもサンドボックス内で実行されます。

1. [`cws-agent` のインストール手順](https://github.com/coreweave/cws-agent#install)に従います。
   API キー認証を使用する場合は、起動前にローカルで `OPENAI_API_KEY` をエクスポートしておきます。
   ツールがこのキーをサンドボックスに渡し、Codex のログインコマンドを使って保存します。

2. `[SANDBOX-NAME]` を、英小文字、数字、ハイフンからなる 1～40 文字で、
   先頭が英小文字または数字の名前に置き換えます。`[REPOSITORY-URL]`
   は公開リポジトリの URL に置き換えます。

   ```bash theme={"system"}
   cws-agent launch [SANDBOX-NAME] --agent codex --repo-url [REPOSITORY-URL] --lifetime 8h --permission-mode native
   ```

   スキルまたは Model Context Protocol (MCP) のインポートを確認するプロンプトが表示された場合、
   この例では **Enter** を押してスキップします。Codex はサンドボックスの project ディレクトリで起動します。ワークスペースの
   信頼と認証に関するプロンプトに従って操作します。

   `--permission-mode native` を指定すると、Codex 独自の権限設定がそのまま使用されます。指定しない場合、ラッパーは
   デフォルトで承認プロンプトをスキップします。詳しくは、
   [`cws-agent` の権限モード](https://github.com/coreweave/cws-agent/blob/main/docs/permissions.md)を参照してください。

3. アカウントへのサインインが必要な場合は、TUI を終了してから、サンドボックス内で認証します。

   ```bash theme={"system"}
   cws-agent login [SANDBOX-NAME]
   cws-agent connect [SANDBOX-NAME] --permission-mode native
   ```

   Codex に表示されるログイン手順に従います。ヘッドレス環境でのデバイスサインインやワークスペースの
   制限については、[Codex の認証](https://learn.chatgpt.com/docs/auth)を参照してください。

4. [セッションを確認する](#check-the-session)の手順を実行します。サンドボックスの実行中に後から再接続する場合は、
   同じ `connect` コマンドを使用します。保存済みの Codex
   会話を再開する方法については、[`cws-agent` のセッション](https://github.com/coreweave/cws-agent/blob/main/docs/sessions.md)を参照してください。

<h2 id="create-an-ssh-accessible-sandbox">
  SSH でアクセス可能なサンドボックスを作成する
</h2>

ローカル CLI とデスクトップアプリのどちらを使用する場合も、このセットアップを完了してください。この手順では
Sandboxes ソフトウェア開発キット (SDK) を使用して、Codex がインストールされ、
root 以外の SSH ユーザーとして認証済みのサンドボックスを作成します。`cws-agent` は不要です。

このセットアップでは、[Transport Layer Security (TLS) パススルーエンドポイント](/ja/products/sandboxes/public-endpoints)
と `stunnel` を使用して、エンドポイント経由で SSH 通信を転送します。生成された Python の
`ProxyCommand` が TLS 証明書を検証した後、SSH が
ユーザーのキーを認証し、ホストキーを検証します。app server は公開
リスナーを持ちません。この構成は OpenAI の[ネットワーク公開に関するガイダンス](https://learn.chatgpt.com/docs/remote-connections#authentication-and-network-exposure)に準拠しています。

<h3 id="prepare-the-ssh-client">
  SSH クライアントを準備する
</h3>

Python 3.12 以降、`uv`、OpenSSH がインストールされた macOS または Linux コンピューターを使用します。
デスクトップからアクセスする場合は、OpenAI の
[SSH ホストの手順](https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host)に記載されている、サポート対象のアプリとオペレーティングシステムを使用してください。
このセットアップでは、[前提条件](#prerequisites)で用意したサンドボックスの認証情報と、
API 請求が有効な OpenAI APIキーを使用します。

`[OPENAI-API-KEY]` をお使いの OpenAI APIキーに置き換えます。

```bash theme={"system"}
uv venv --python 3.12
source .venv/bin/activate
uv pip install 'cwsandbox==1.14.2'
export OPENAI_API_KEY="[OPENAI-API-KEY]"
```

生成された SSH 設定では、TLS フォワーダーの実行にこの Python インタープリターの絶対パスを使用します。サンドボックスを使用している間は、Python のインストールと出力ディレクトリを
削除せず、利用可能な状態のままにしてください。

専用の SSH キーを作成し、実行中の SSH エージェントに読み込みます。使用されていないファイル名を選択し、
プロンプトが表示されたらパスフレーズを入力してください。

```bash theme={"system"}
ssh-keygen -t ed25519 -f ~/.ssh/cw-codex
ssh-add ~/.ssh/cw-codex
```

秘密鍵はお使いのコンピューターから外部に出ることはありません。セットアップスクリプトがサンドボックスにコピーするのは、
公開鍵のみです。

<h3 id="create-the-ssh-sandbox">
  SSH サンドボックスを作成する
</h3>

以下の内容を `create_codex_ssh.py` ファイルに保存します。このスクリプトは 8 時間有効なサンドボックスを作成し、
Codex `0.154.0` をインストールして、公開鍵による SSH
認証を使用する非 root の `agent` アカウントを設定します。OpenAI キーは標準入力 (stdin) 経由で `codex login` に渡されるため、
キーがサンドボックスの作成設定に保存されることはありません。Codex のログイン情報は
サンドボックス内に保存されます。

また、このスクリプトは有効期間 1 日の TLS 証明書を作成し、認証済みの Sandboxes SDK を使用して公開
証明書と SSH ホストキーを取得します。生成される
クライアント設定では、この両方が検証されます。再接続に必要なため、出力ディレクトリは削除せずに保持してください。

<Accordion title="サンドボックスのセットアップスクリプト">
  ```python title="create_codex_ssh.py" theme={"system"}
  import os
  from pathlib import Path
  import shlex
  import sys

  from cwsandbox import Endpoint, Sandbox, Service

  if len(sys.argv) != 4:
      raise SystemExit(
          "Usage: python create_codex_ssh.py REPOSITORY_URL SSH_KEY OUTPUT_DIR"
      )
  repository, identity_arg, directory_arg = sys.argv[1:]
  identity = Path(identity_arg).expanduser().resolve()
  if not identity.is_file():
      raise SystemExit("SSH private key not found. Generate the key pair first.")
  public_key = Path(str(identity) + ".pub").read_bytes()
  api_key = os.environ["OPENAI_API_KEY"]
  if not api_key:
      raise SystemExit("Set OPENAI_API_KEY first.")
  directory = Path(directory_arg).expanduser().resolve()
  directory.mkdir(mode=0o700, parents=True, exist_ok=False)
  sandbox = Sandbox.run(
      container_image="node:22-bookworm",
      resources={"cpu": "2", "memory": "4Gi"},
      max_lifetime_seconds=8 * 3600,
      services=[
          Service(
              port=8443,
              name="ssh",
              visibility="public",
              endpoint=Endpoint(kind="tls_passthrough"),
          )
      ],
  )

  def run(command):
      result = sandbox.exec(command, timeout_seconds=900).result()
      if result.returncode != 0:
          details = (result.stdout + result.stderr).replace(api_key, "[REDACTED]")
          raise RuntimeError(details[-3000:])
      return result.stdout

  try:
      (directory / "sandbox-id").write_text(sandbox.sandbox_id + "\n")
      print("Sandbox created; ID saved in", directory / "sandbox-id", flush=True)
      sandbox.wait()
      address = next(
          item.address for item in sandbox.service_addresses if item.port == 8443
      )
      host, port = address.rsplit(":", 1)
      run(
          [
              "bash",
              "-c",
              """
  set -eu
  apt-get update -qq
  DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openssh-server stunnel4 bubblewrap
  npm install --global @openai/codex@0.154.0
  useradd --create-home --shell /bin/bash agent
  usermod --password '*' agent
  install -d -m 700 -o agent -g agent /home/agent/.ssh
  install -d -m 755 /run/sshd /workspace
  mkdir -p /etc/codex-ssh
  chmod 700 /etc/codex-ssh
  """,
          ]
      )
      sandbox.write_file("/home/agent/.ssh/authorized_keys", public_key).result()
      run(
          [
              "bash",
              "-c",
              "chmod 600 /home/agent/.ssh/authorized_keys; chown agent:agent /home/agent/.ssh/authorized_keys",
          ]
      )
      run(["git", "clone", "--", repository, "/workspace/project"])
      run(["chown", "-R", "agent:agent", "/workspace/project"])
      login = sandbox.exec(
          ["runuser", "-u", "agent", "--", "codex", "login", "--with-api-key"],
          stdin=True,
          timeout_seconds=60,
      )
      login.stdin.write((api_key + "\n").encode()).result()
      login.stdin.close().result()
      if login.result().returncode != 0:
          raise RuntimeError("Codex authentication failed.")
      run(
          [
              "openssl",
              "req",
              "-x509",
              "-newkey",
              "rsa:2048",
              "-noenc",
              "-keyout",
              "/etc/codex-ssh/tls.key",
              "-out",
              "/etc/codex-ssh/tls.crt",
              "-days",
              "1",
              "-subj",
              "/CN=codex-sandbox",
              "-addext",
              f"subjectAltName=DNS:{host}",
          ]
      )
      sandbox.write_file(
          "/etc/codex-ssh/sshd_config",
          b"""Port 2222
  ListenAddress 127.0.0.1
  HostKey /etc/ssh/ssh_host_ed25519_key
  AuthorizedKeysFile .ssh/authorized_keys
  PubkeyAuthentication yes
  PasswordAuthentication no
  KbdInteractiveAuthentication no
  PermitRootLogin no
  AllowUsers agent
  AllowTcpForwarding local
  X11Forwarding no
  Subsystem sftp internal-sftp
  """,
      ).result()
      sandbox.write_file(
          "/etc/codex-ssh/stunnel.conf",
          b"""pid = /run/codex-stunnel.pid
  output = /var/log/codex-stunnel.log
  [ssh]
  accept = 0.0.0.0:8443
  connect = 127.0.0.1:2222
  cert = /etc/codex-ssh/tls.crt
  key = /etc/codex-ssh/tls.key
  """,
      ).result()
      run(["chmod", "600", "/etc/codex-ssh/tls.key"])
      run(
          [
              "/usr/sbin/sshd",
              "-f",
              "/etc/codex-ssh/sshd_config",
              "-E",
              "/var/log/codex-sshd.log",
          ]
      )
      run(["stunnel", "/etc/codex-ssh/stunnel.conf"])
      certificate = directory / "tls.crt"
      certificate.write_bytes(sandbox.read_file("/etc/codex-ssh/tls.crt").result())
      host_key = (
          sandbox.read_file("/etc/ssh/ssh_host_ed25519_key.pub").result().decode().strip()
      )
      known_hosts = directory / "known_hosts"
      known_hosts.write_text("cw-codex " + host_key + "\n")
      forwarder = directory / "tls_proxy.py"
      forwarder.write_text('''"""Forward SSH through verified TLS, with backpressure in both directions."""
  import asyncio
  import ssl
  import sys

  async def main():
      host, port, certificate = sys.argv[1:]
      context = ssl.create_default_context(cafile=certificate)
      remote_reader, remote_writer = await asyncio.open_connection(
          host, int(port), ssl=context, server_hostname=host
      )
      local_reader = asyncio.StreamReader()
      transport, _ = await asyncio.get_running_loop().connect_read_pipe(
          lambda: asyncio.StreamReaderProtocol(local_reader), sys.stdin.buffer
      )
      async def upload():
          while data := await local_reader.read(65536):
              remote_writer.write(data)
              await remote_writer.drain()
      def write_output(data):
          sys.stdout.buffer.write(data)
          sys.stdout.buffer.flush()
      async def download():
          while data := await remote_reader.read(65536):
              await asyncio.to_thread(write_output, data)
      tasks = [asyncio.create_task(upload()), asyncio.create_task(download())]
      try:
          done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
          for task in done:
              task.result()
      finally:
          for task in tasks:
              task.cancel()
          transport.close()
          remote_writer.close()
          await remote_writer.wait_closed()

  try:
      asyncio.run(main())
  except (OSError, ssl.SSLError) as error:
      print(f'TLS proxy: {error}', file=sys.stderr)
      sys.exit(1)
  ''')
      proxy = shlex.join(
          [sys.executable, str(forwarder), "%h", "%p", str(certificate)]
      )
      config = directory / "ssh_config"
      config.write_text(f'''Host cw-codex
      HostName {host}
      Port {port}
      User agent
      IdentityFile "{identity}"
      IdentitiesOnly yes
      HostKeyAlias cw-codex
      UserKnownHostsFile "{known_hosts}"
      StrictHostKeyChecking yes
      ServerAliveInterval 30
      ProxyCommand {proxy}
  ''')
      print("SSH config:", config, flush=True)
  except BaseException as error:
      try:
          sandbox.stop().result()
      except BaseException:
          error.add_note(
              f"Automatic cleanup failed. Stop sandbox {sandbox.sandbox_id} manually."
          )
      raise
  ```
</Accordion>

`[REPOSITORY-URL]` を公開 Git リポジトリの URL に置き換え、
リポジトリ外に新しい出力ディレクトリを選択します。

```bash theme={"system"}
python create_codex_ssh.py [REPOSITORY-URL] ~/.ssh/cw-codex ~/.ssh/cw-codex-session
```

セットアップが成功すると、`ssh_config` ファイルの場所が出力され、
サンドボックスは実行中のままになります。出力ディレクトリには、`sandbox-id`、`tls.crt`、
`known_hosts` の各ファイルに加えて、`tls_proxy.py` フォワーダーも格納されます。サンドボックスの作成後にセットアップが失敗した場合、
スクリプトはサンドボックスの停止を試みます。停止にも失敗した場合は、
手動でクリーンアップできるよう、元のエラーにサンドボックス ID が含まれます。

Codex を接続する前に、SSH 接続を確認します。

```bash theme={"system"}
ssh -F ~/.ssh/cw-codex-session/ssh_config cw-codex 'id -un; codex --version; test -d /workspace/project/.git && echo repository-ready'
```

出力に `agent`、`codex-cli 0.154.0`、`repository-ready` が含まれていることを確認してください。
最初の接続に失敗した場合は、エンドポイントとサービスの起動が完了するのを待ってから
再試行してください。それでも接続に失敗する場合は、Sandboxes SDK を使用して `/var/log/codex-sshd.log` と
`/var/log/codex-stunnel.log` の各ファイルを確認してください。

SSH 接続を確認したら、
[ローカル CLI](#connect-your-local-cli-to-codex-app-server) または
[デスクトップアプリとモバイルアプリ](#use-the-desktop-and-mobile-apps) の手順に進みます。

<h2 id="connect-your-local-cli-to-codex-app-server">
  ローカルの CLI を Codex app server に接続する
</h2>

まず [SSH でアクセス可能なサンドボックスを作成する](#create-an-ssh-accessible-sandbox)
を完了してください。サポートされている Node.js の長期サポート (LTS) リリースを使用して、同じバージョンの
Codex をローカルにインストールします。npm パッケージでは、最小要件として Node.js 16 以降が指定されています。

```bash theme={"system"}
npm install --global @openai/codex@0.154.0
```

<Warning>
  OpenAI は、app server の WebSocket トランスポートを実験的な機能と位置付けており、
  本番ワークロードでのサポート対象外としています。この例では、リスナーと転送先ポートを
  ループバックアドレスにバインドし、トラフィックを SSH 経由で転送します。ただし、これらの
  ホスト上の他のプロセスからもループバックポートにアクセスできます。信頼できるホストを使用してください。
</Warning>

SSH トンネル経由でローカル CLI を接続します。

1. サンドボックスの project ディレクトリで app server を起動します。このコマンドを使用すると、app server が終了した場合でも起動時の
   出力が保存されます。ターミナルは開いたままにしてください。

   ```bash theme={"system"}
   ssh -t -F ~/.ssh/cw-codex-session/ssh_config cw-codex 'cd /workspace/project && exec codex app-server --listen ws://127.0.0.1:4500 > /home/agent/codex-app-server.log 2>&1'
   ```

   `-t` オプションによってリモートターミナルが割り当てられるため、**Ctrl+C** がリスナーに送られます。

2. 2 つ目のターミナルで、ローカルポートをこのリスナーに転送し、
   接続を維持します。

   ```bash theme={"system"}
   ssh -F ~/.ssh/cw-codex-session/ssh_config -N -o ExitOnForwardFailure=yes -L 127.0.0.1:4500:127.0.0.1:4500 cw-codex
   ```

3. 3 つ目のターミナルで、ローカルの TUI を接続し、リモートの
   project ディレクトリを明示的に指定します。

   ```bash theme={"system"}
   codex --remote ws://127.0.0.1:4500 --cd /workspace/project
   ```

4. TUI に `/workspace/project` が表示されていることを確認してから、
   [セッションを確認する](#check-the-session) の手順を実行します。接続に失敗した場合は、
   保存されている起動時の出力を確認してください。

   ```bash theme={"system"}
   ssh -F ~/.ssh/cw-codex-session/ssh_config cw-codex 'cat /home/agent/codex-app-server.log'
   ```

リスナーの実行中に保存済みの会話を再開するには、SSH トンネルを
再確立してから、リモートセッションピッカーを開きます。

```bash theme={"system"}
codex resume --remote ws://127.0.0.1:4500 --cd /workspace/project
```

再開する会話を選択します。新しい会話を開始する場合は、
元の `codex --remote` コマンドを使用します。

このリスナーは、デスクトップアプリが管理する app server とは別のものです。
両者の間で会話を共有できるかどうかは検証されていません。OpenAI の
[ローカル TUI 接続リファレンス](https://learn.chatgpt.com/docs/app-server#connect-the-cli-terminal-ui)を参照してください。

作業が終わったら TUI を終了し、リスナー用のターミナルと
転送用のターミナルで **Ctrl+C** を押します。
[SSH サンドボックスへの再接続と停止](#reconnect-and-stop-the-ssh-sandbox)
の手順に従って、ファイルを取得し、コンピュートを停止します。

<h2 id="use-the-desktop-and-mobile-apps">
  デスクトップアプリとモバイルアプリを使用する
</h2>

まず [SSH でアクセス可能なサンドボックスを作成する](#create-an-ssh-accessible-sandbox)
の手順を完了してください。デスクトップアプリでサンドボックスを SSH projectとして追加したら、Remote を使用して
ペアリング済みのスマートフォンから作業を続けられます。SSH 接続はデスクトップ側のホストが維持します。

<h3 id="connect-the-desktop-app">
  デスクトップアプリを接続する
</h3>

サンドボックスをリモートprojectとして追加し、Codex がそのファイルシステムに書き込めることを確認します。

1. `~/.ssh/cw-codex-session/ssh_config` ファイルから、生成された `Host cw-codex` ブロックをコピーします。これを `~/.ssh/config` ファイル内の `Host *` のデフォルト設定より前に貼り付けます。既存の `Host cw-codex` エントリがある場合は、重複して追加せずに置き換えてください。
2. `ssh cw-codex 'codex --version'` を実行します。認証エラーやホストキーのエラーが発生した場合は、解決してから次に進んでください。
3. デスクトップアプリで **Settings > Connections** を開き、`cw-codex` SSH ホストを追加するか有効にします。
4. リモートprojectのフォルダーとして `/workspace/project` を選択し、projectを保存します。
5. そのリモートprojectを開いて会話を開始します。シークレットではない一意の値を `/workspace/project/sandbox-proof.txt` ファイルに書き込むよう、Codex に依頼します。
6. ターミナルから、結果を別途確認します。

   ```bash theme={"system"}
   ssh cw-codex 'cat /workspace/project/sandbox-proof.txt'
   ```

ファイルの内容が、依頼した値と一致していれば成功です。

デスクトップアプリは、SSH ユーザーのログインシェルを使用してリモートのapp serverを起動します。そのため、Codex はそのユーザー環境にインストールされ、認証済みである必要があります。詳しくは、OpenAI の[デスクトップ SSH セットアップ](https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host)を参照してください。

<h3 id="mobile-and-another-desktop-through-remote">
  Remote を介したモバイルや別のデスクトップからの接続
</h3>

OpenAI の Remote 機能は、ペアリングされたホストを介して、サポートされているデスクトップアプリとモバイルアプリを接続します。
ドキュメントに記載されているモバイルのセットアップは、Mac または Windows ホスト上の ChatGPT デスクトップアプリから開始します。両方のデバイスで同じアカウントとワークスペースを使用してください。
組織設定やロールアウトの提供状況によっては、アクセスが制限される場合があります。

スマートフォンからサンドボックスで作業するには、まずそのデスクトップホストをサンドボックスの SSH project に接続します。
次に、スマートフォンをデスクトップホストとペアリングします。iOS または Android 版の ChatGPT で **Remote** を使用します。スマートフォンはデスクトップホストに接続し、そのデスクトップホストがサンドボックスに接続します。デスクトップアプリは起動したまま、スリープさせず、オンラインの状態を維持しておく必要があります。**Control other devices** が利用可能な場合は、サポートされている別の Mac または Windows デスクトップアプリからも同じホストに接続できます。

OpenAI の [Remote セットアップ手順](https://learn.chatgpt.com/docs/remote-connections)に従ってください。
app serverの WebSocket URL は、モバイルのペアリング用 URL ではありません。また、Agents API の
`codex exec-server --remote` 接続でも、モバイルデバイスはペアリングされません。

<h3 id="session-continuity-and-other-entry-points">
  セッションの継続性とその他のエントリポイント
</h3>

Remote では、接続先ホストのチャットをペアリング済みのデバイスから継続できます。ただし、
`codex --remote` を直接実行する例で開始した会話が、
個別に設定したデスクトップの SSH project に表示されるとは限りません。
このセットアップでは、こうしたインターフェース間でのセッションの引き継ぎは未検証として扱ってください。

公開されている Remote のセットアップ手順には、モバイルクライアントとサポート対象のデスクトップクライアントが記載されています。
ChatGPT や Codex の Web サイトをこのサンドボックスセッションに接続する方法は記載されていません。Web サイトからの
アクセスは、このガイドで扱うインターフェースの対象外です。

一部の Codex ビルドでは、実験的な `codex remote-control start` コマンドと
`codex remote-control pair` コマンドが公開されています。これらはapp serverのデーモンとペアリングを管理するものですが、
公開されているモバイル向けの手順からは、ヘッドレスな Linux サンドボックスでのペアリングフローがサポートされているかどうかは確認できません。
このガイドでは、これらのコマンドを Claude Remote Control と同等の検証済み機能としては扱いません。
利用する前に、インストール済みの CLI のヘルプと OpenAI の最新のガイダンスを確認してください。

<h2 id="check-the-session">
  セッションを確認する
</h2>

[サンドボックスで Codex CLI を実行する](#run-codex-cli-in-a-sandbox)または
[ローカル CLI を Codex app server に接続する](#connect-your-local-cli-to-codex-app-server)の手順を実施した場合は、
Codex がサンドボックスのファイルシステムに書き込めることを検証します。デスクトップからアクセスする場合は、
[デスクトップアプリを接続する](#connect-the-desktop-app)の手順に従ってください。

`[PROOF-VALUE]` を機密情報ではない一意の値に置き換えてから、接続済みの Codex TUI で次のプロンプトを
送信します。

```text theme={"system"}
テキスト [PROOF-VALUE] を一字一句そのまま /workspace/project/sandbox-proof.txt に書き込み、その後ファイルを読み取って内容を確認してください。
```

プロンプトが表示された場合は、書き込みを承認します。TUI を終了し、お使いのセットアップに応じたコマンドを使用して、ローカルのターミナルからファイルを別途確認します。

<Tabs>
  <Tab title="cws-agent">
    ```bash theme={"system"}
    cws-agent exec [SANDBOX-NAME] 'cat /workspace/project/sandbox-proof.txt'
    ```
  </Tab>

  <Tab title="SSH 経由のローカル CLI">
    ```bash theme={"system"}
    ssh -F ~/.ssh/cw-codex-session/ssh_config cw-codex 'cat /workspace/project/sandbox-proof.txt'
    ```
  </Tab>
</Tabs>

値が一致すれば、エージェントがこのサンドボックスのファイルシステムに書き込んだことを確認できます。
ただし、モバイルのペアリングや別のアプリからのアクセスまで確認できるわけではありません。

<h2 id="reconnect-and-stop-the-ssh-sandbox">
  SSH サンドボックスへの再接続と停止
</h2>

サンドボックスの実行中は、引き続き同じ `cw-codex` ホストとprojectを使用します。
SSH 接続やデスクトップアプリを閉じても、サンドボックスのコンピュートは停止しません。

サンドボックスを停止する前に、作業内容を Git に保存するか、必要なファイルをコピーしておいてください：

```bash theme={"system"}
scp -F ~/.ssh/cw-codex-session/ssh_config cw-codex:/workspace/project/sandbox-proof.txt ./sandbox-proof.txt
```

保存しておいたサンドボックスの ID を使用して、サンドボックスを停止します：

```python theme={"system"}
from pathlib import Path

from cwsandbox import Sandbox

sandbox_id = Path("~/.ssh/cw-codex-session/sandbox-id").expanduser().read_text().strip()
sandbox = Sandbox.from_id(sandbox_id).result()
sandbox.stop().result()
```

この例では Persistent Volume やスナップショットを使用しません。サンドボックスが停止するか有効期限切れになると、
そのファイル、ログイン状態、エンドポイントにはアクセスできなくなります。やり直すには、新しい
サンドボックスと出力ディレクトリを作成し、`Host cw-codex` ブロックを新しい
設定に置き換えてください。エンドポイント、TLS 証明書、SSH ホストキーはサンドボックスごとに新しく発行されます。

<h2 id="keep-results-and-stop">
  結果を保持して停止する
</h2>

ローカルの CLI とデスクトップアプリの場合は、
[SSH サンドボックスに再接続して停止する](#reconnect-and-stop-the-ssh-sandbox)の手順に従ってください。

`cws-agent` の場合は、ワークスペースのスナップショットを保存してから、コンピュートを停止します。

```bash theme={"system"}
cws-agent down [SANDBOX-NAME]
```

スナップショットの作成に失敗した場合は、再試行する前に報告されたエラーを確認してください。保存せずに
停止するには、`cws-agent down [SANDBOX-NAME] --no-snapshot` を使用します。

TUI を終了してもコンピュートは停止しません。サンドボックスを停止するか有効期限が切れると、
そのプロセスは終了します。コンピュートを再開するには、保存済みのファイルをリストアしてから Codex を
再起動します。スナップショットには実行中のプロセスは保持されません。保持する内容を選択する際は、保存済みの Codex の
認証ファイルとセッションファイルを機密情報として扱ってください。

<h2 id="troubleshoot">
  トラブルシューティング
</h2>

よくある問題は、以下の項目を確認して解決してください。

* 認証に失敗する: サンドボックスのプロビジョニング用認証情報、Codex
  のモデル認証、SSH キーを区別してください。これらはそれぞれ用途が異なります。
* app serverのフラグが拒否される: ローカルとサンドボックスで `codex --version`
  の出力を比較してください。ローカル CLI の例では、ドキュメントに記載されている WebSocket フラグが必要です。
* TUI は接続できるが処理が失敗する: モデルへのアクセス、請求、ワークスペースの
  信頼設定、承認設定を確認してください。トランスポート接続が確立できても、それだけでモデルにアクセスできるとは限りません。
* 接続が切断される: サンドボックスの実行中に再接続してください。エンドポイントや
  トランスポートのタイムアウトによってサンドボックスの有効期間が延長されることはなく、処理中のターンが完了したことも保証されません。
* モバイルアプリでRemoteが利用できない: OpenAI のアカウント、ワークスペース、
  ホスト、ロールアウトに関する要件を確認してください。app serverを起動するだけでは有効になりません。
