[PR #309] [MERGED] feat: add native Codex sessions to aenv CLI #336

Closed
opened 2026-10-29 14:22:20 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/309
Author: @Primary33
Created: 9/21/2026
Status: ✅ Merged
Merged: 9/24/2026
Merged by: @yingdi-shan

Base: main ← Head: docs/agentenv-codex-harness


📝 Commits (2)

  • 7961162 feat(aenv): add native Codex sandbox sessions
  • 56897dd docs(aenv): document Codex sandbox workflow

📊 Changes

17 files changed (+3133 additions, -3 deletions)

View changed files

📝 Cargo.lock (+3 -0)
📝 crates/aenv/Cargo.toml (+4 -1)
📝 crates/aenv/src/client/mod.rs (+4 -0)
📝 crates/aenv/src/client/sandboxes.rs (+2 -0)
📝 crates/aenv/src/commands/build.rs (+22 -0)
➕ crates/aenv/src/commands/codex/assets/Dockerfile (+18 -0)
➕ crates/aenv/src/commands/codex/guest.rs (+714 -0)
➕ crates/aenv/src/commands/codex/mod.rs (+115 -0)
➕ crates/aenv/src/commands/codex/project.rs (+536 -0)
➕ crates/aenv/src/commands/codex/runtime.rs (+1013 -0)
➕ crates/aenv/src/commands/codex/socket.rs (+556 -0)
📝 crates/aenv/src/commands/download.rs (+1 -1)
📝 crates/aenv/src/commands/mod.rs (+1 -0)
📝 crates/aenv/src/main.rs (+3 -0)
📝 docs/src/SUMMARY.md (+1 -0)
📝 docs/src/getting-started/aenv-cli/index.md (+2 -1)
➕ docs/src/use-cases/codex.md (+138 -0)

📄 Description

What

Add aenv codex setup, start, resume, and finish so users can work on their projects through the native Codex terminal with execution in an AgentENV sandbox.

Why

Users should be able to start a sandbox coding session from the installed CLI. Template assets and connection logic ship in aenv; no repository checkout, separate launcher, or Python runtime is needed for the integration.

None.

Scope and non-goals

The interactive aenv command, bundled executor template, project transfer and session lifecycle, and a Use Cases guide. Server APIs and storage formats are unchanged.

Design and behavior changes

  • setup prepares the embedded executor template through the existing aenv builder and saves only its name. It does not require a local Codex installation; start and resume check the local version. Later sessions reuse the template.
  • start <project> uploads working files, then opens the unmodified Codex CLI. The host app-server uses the user's native Codex configuration and authentication. A process-local executor URL connects it to the sandbox with local execution disabled; no model credentials are copied into aenv settings or the guest.
  • Developer instructions and terminal display preferences follow native Codex settings. The launcher imposes no model-turn deadline; network request timeouts and sandbox lease renewal remain in place.
  • A private Unix-socket gateway sends workspace helper RPCs to an auxiliary app-server in the guest, so native /diff reads sandbox files. The executor and workspace service connect through authenticated AgentENV proxy connections; model credentials stay on the host.
  • /quit stops active work, saves a project copy and patch, and pauses the sandbox. resume restores the sandbox and conversation. finish saves before deletion; recover is an alias.
  • After exporting files, finish persists a deletion-pending state before sending DELETE. Repeating finish retries deletion without reconnecting or exporting again, accepts an already-deleted sandbox, and completes the final local status update. Errors retain the saved path and recovery instructions; resume rejects sessions whose deletion has started.
  • Interactive exit and finish share the save/cleanup path. Downloads reuse the existing CLI stream writer. Conversation history is stored by Codex; thread-id is the sole conversation ID record and is rewritten only when the ID changes. The wrapper caches thread eligibility rather than complete thread objects and does not record completed results or write a duplicate event journal.
  • Rust manages guest services through envd using a unique tag for each startup. A Bash supervisor remains the session leader and signals its own process group: TERM, then KILL after five seconds. The CLI never sends group signals using PID numbers from a /proc snapshot, so PID/PGID reuse cannot redirect cleanup to an unrelated group. Process snapshots only determine when shutdown has finished. File export uses a validated NUL-delimited Git file list and system tar; no Python helper scripts are shipped or invoked.
  • Sessions renew their five-minute lease every 30 seconds. Connection failures and failed exports retain the sandbox for recovery. Exclusive session locks prevent competing launchers.
  • Uploads respect Git ignores, include working changes, and exclude Git history, caches, environment files, and common private keys. Each download creates a separate save after checking archive paths and symlinks. The source project is never overwritten.
Native Codex UI -> aenv gateway -> host Codex app-server -> model API
                       |                   |
                       |                   +-> sandbox exec-server
                       +-> sandbox workspace service (/diff, files, processes)

Compatibility and operations

  • Public API, generated protocol, and storage formats: unchanged.
  • Client requirements: Linux, Git, and Codex 0.155.1. start and resume need an interactive terminal. Node.js is needed for npm installation of Codex. The template still includes Python for user project tasks; the integration does not depend on it. First-time template builds use the existing aenv-buildctl installed beside aenv.
  • Model configuration and authentication: managed by Codex under ~/.codex or CODEX_HOME, including its configured credential store and provider environment variables. aenv stores only the template name in ~/.config/aenv/codex.json; it neither prompts for nor copies model credentials. --model remains a temporary native Codex override. Sessions default to ~/.local/share/aenv/codex/sessions/; XDG directories are honored. Resume with the same Codex home.
  • Upgrade/rollback: install the updated aenv binary; no server migration. Local and guest Codex versions must match the pinned version's experimental app-server protocol.
  • Interactive exit retains a paused sandbox and local saves. Run finish when done. Lease expiry auto-pauses a sandbox after abrupt launcher termination.

Validation

cargo fmt -p aenv -- --check
cargo clippy --locked --release -p aenv --all-targets -- -D warnings
cargo test --locked --release -p aenv --bin aenv   # 109 passed
git diff --check

The checks above were run as a non-root user on the existing Linux test host for the deletion-recovery fix. Four new regression tests cover failed DELETE retries (including authorization errors), a lost DELETE response, a failed post-delete manifest write, and refusing deletion when the pending state cannot be persisted. They use local mock HTTP endpoints; the live sandbox/model workflow was not rerun for this fix.

Earlier live checks on a Linux AgentENV deployment, running the compiled binary outside the source tree. The previous cleanup validation rechecked cleanup, export failure, and recovery; the other feature checks below preceded that cleanup change:

  • Built a new template from the embedded Dockerfile; reused an existing template.
  • Repeated the complete native workflow in a test template with neither python nor python3 installed: read a random value present only inside the sandbox, edit files, inspect /diff, exit with saved files, and resume the same conversation for another edit.
  • finish saved results and deleted the sandbox.
  • An unsafe export was rejected without deleting the sandbox; finish recovered the work after the export issue was corrected.
  • Rechecked native start/resume, /diff, and failed-export recovery. Recovery works without model credentials, and repeated finish is safe. Non-terminal start/resume is rejected before creating or connecting a sandbox.
  • Latest cleanup validation used a template with neither python nor python3: an envd-tagged supervisor without a persisted record was recovered, TERM-ignoring descendants were stopped, and a stale record naming an unrelated group left that group running. An unsafe export retained the sandbox; correcting the export allowed finish to save and delete it.
  • Forcibly killing a supervisor caused cleanup to refuse numeric-PID fallback, preserve its remaining children, and pause the sandbox before saving. Both disposable validation sandboxes were confirmed deleted.
  • Linux regression tests exercise real supervisor TERM/KILL escalation and orphan cleanup after the service exits, preserving an unrelated process. A mock envd test replaces a dead service with another service at the same numeric PID and verifies that cleanup uses only the original unique tag.
  • Original project files remained unchanged. Disposable validation sandboxes were confirmed deleted.
  • Unit tests cover command parsing, template-only settings, conflicting execution configuration, private files and locking, Git file selection, literal filenames (including newlines, leading dashes, and non-UTF-8 names), hard links, archive traversal and symlink chains, stale process records, workspace RPC routing, helper-thread filtering, conversation ID recovery and write failures, and relay authentication/header isolation with binary frames.
  • Native Codex file-based API authentication (codex login --with-api-key) and custom provider env_key authentication both completed interactive sandbox tasks, /diff, saving and resume. Two overlapping sessions reused one native Codex home with separate sandbox files and conversations. Setup worked without any model configuration or credentials. Provider settings were preserved; native Codex recorded its own project trust setting.
  • With custom developer instructions and tui.alternate_screen = "always", the model followed the configured instructions and the native UI entered and restored the alternate screen. Sandbox-only file access, /diff, saving, resume with a follow-up task, and finish all passed. Start/resume help no longer exposes a wrapper turn timeout.
  • Setup succeeded with a nonexistent local Codex executable and home. Resume used the standalone thread-id despite a stale legacy ID in session.json, and unchanged IDs retained the same file inode across resume and follow-up turns. Killing the owned launcher process group with SIGKILL still allowed the same sandbox and conversation to resume; finish then saved and deleted the test sandbox.
  • An existing environments.toml was rejected before a sandbox or session was created. Template setup discarded legacy model fields without migrating credentials.
  • Updated documentation links and command examples checked. Full mdBook rendering was not rerun; mdBook is unavailable in this build environment.

Server, storage, and Go suites were skipped because those components are unchanged.

Risks and reviewer notes

Codex 0.155.1 prioritizes environments.toml over the per-process sandbox URL. The launcher rejects that configuration without changing the file; users can configure a separate native Codex home. Earlier draft model fields are ignored and removed on the next setup. Conversation history in an earlier draft's private session home is not automatically migrated: finish can save that project, then start opens it under native Codex configuration.

Codex 0.155.1's native @ picker searches the CLI machine even in remote mode. The guide tells users to type relative sandbox paths instead; model file access and native /diff work against the sandbox.

Shutdown requires the service supervisor to remain available. Services from earlier drafts without supervisors, or services whose supervisors were externally killed, are retained for manual cleanup if live group members remain. The CLI refuses unsafe PID-based fallback. This uses the existing Bash/envd facilities and works with the default Linux 6.1 guest; no template rebuild or new runtime dependency is required.

Model commands run with automatic approval inside the sandbox. Review commands/codex/runtime.rs for lifecycle and recovery, guest.rs for sandbox process ownership and cleanup, socket.rs for RPC boundaries, and project.rs for file transfer checks.

Checklist

  • One coherent change with no unrelated refactoring.
  • New behavior covered by unit tests and live sandbox validation.
  • No credentials or private infrastructure details in logs or examples committed here.
  • No generated code manually modified.
  • User documentation updated.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/kvcache-ai/AgentENV/pull/309 **Author:** [@Primary33](https://github.com/Primary33) **Created:** 9/21/2026 **Status:** ✅ Merged **Merged:** 9/24/2026 **Merged by:** [@yingdi-shan](https://github.com/yingdi-shan) **Base:** `main` ← **Head:** `docs/agentenv-codex-harness` --- ### 📝 Commits (2) - [`7961162`](https://github.com/kvcache-ai/AgentENV/commit/7961162dcf48e9b8b3196cdadd9f25919d93daaf) feat(aenv): add native Codex sandbox sessions - [`56897dd`](https://github.com/kvcache-ai/AgentENV/commit/56897ddd007e787175a976793c0eb3dced52995c) docs(aenv): document Codex sandbox workflow ### 📊 Changes **17 files changed** (+3133 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `Cargo.lock` (+3 -0) 📝 `crates/aenv/Cargo.toml` (+4 -1) 📝 `crates/aenv/src/client/mod.rs` (+4 -0) 📝 `crates/aenv/src/client/sandboxes.rs` (+2 -0) 📝 `crates/aenv/src/commands/build.rs` (+22 -0) ➕ `crates/aenv/src/commands/codex/assets/Dockerfile` (+18 -0) ➕ `crates/aenv/src/commands/codex/guest.rs` (+714 -0) ➕ `crates/aenv/src/commands/codex/mod.rs` (+115 -0) ➕ `crates/aenv/src/commands/codex/project.rs` (+536 -0) ➕ `crates/aenv/src/commands/codex/runtime.rs` (+1013 -0) ➕ `crates/aenv/src/commands/codex/socket.rs` (+556 -0) 📝 `crates/aenv/src/commands/download.rs` (+1 -1) 📝 `crates/aenv/src/commands/mod.rs` (+1 -0) 📝 `crates/aenv/src/main.rs` (+3 -0) 📝 `docs/src/SUMMARY.md` (+1 -0) 📝 `docs/src/getting-started/aenv-cli/index.md` (+2 -1) ➕ `docs/src/use-cases/codex.md` (+138 -0) </details> ### 📄 Description ## What Add `aenv codex setup`, `start`, `resume`, and `finish` so users can work on their projects through the native Codex terminal with execution in an AgentENV sandbox. ## Why Users should be able to start a sandbox coding session from the installed CLI. Template assets and connection logic ship in `aenv`; no repository checkout, separate launcher, or Python runtime is needed for the integration. ## Related issue None. ## Scope and non-goals The interactive aenv command, bundled executor template, project transfer and session lifecycle, and a Use Cases guide. Server APIs and storage formats are unchanged. ## Design and behavior changes - `setup` prepares the embedded executor template through the existing aenv builder and saves only its name. It does not require a local Codex installation; `start` and `resume` check the local version. Later sessions reuse the template. - `start <project>` uploads working files, then opens the unmodified Codex CLI. The host app-server uses the user's native Codex configuration and authentication. A process-local executor URL connects it to the sandbox with local execution disabled; no model credentials are copied into aenv settings or the guest. - Developer instructions and terminal display preferences follow native Codex settings. The launcher imposes no model-turn deadline; network request timeouts and sandbox lease renewal remain in place. - A private Unix-socket gateway sends workspace helper RPCs to an auxiliary app-server in the guest, so native `/diff` reads sandbox files. The executor and workspace service connect through authenticated AgentENV proxy connections; model credentials stay on the host. - `/quit` stops active work, saves a project copy and patch, and pauses the sandbox. `resume` restores the sandbox and conversation. `finish` saves before deletion; `recover` is an alias. - After exporting files, `finish` persists a `deletion-pending` state before sending DELETE. Repeating `finish` retries deletion without reconnecting or exporting again, accepts an already-deleted sandbox, and completes the final local status update. Errors retain the saved path and recovery instructions; `resume` rejects sessions whose deletion has started. - Interactive exit and `finish` share the save/cleanup path. Downloads reuse the existing CLI stream writer. Conversation history is stored by Codex; `thread-id` is the sole conversation ID record and is rewritten only when the ID changes. The wrapper caches thread eligibility rather than complete thread objects and does not record completed results or write a duplicate event journal. - Rust manages guest services through envd using a unique tag for each startup. A Bash supervisor remains the session leader and signals its own process group: TERM, then KILL after five seconds. The CLI never sends group signals using PID numbers from a `/proc` snapshot, so PID/PGID reuse cannot redirect cleanup to an unrelated group. Process snapshots only determine when shutdown has finished. File export uses a validated NUL-delimited Git file list and system tar; no Python helper scripts are shipped or invoked. - Sessions renew their five-minute lease every 30 seconds. Connection failures and failed exports retain the sandbox for recovery. Exclusive session locks prevent competing launchers. - Uploads respect Git ignores, include working changes, and exclude Git history, caches, environment files, and common private keys. Each download creates a separate save after checking archive paths and symlinks. The source project is never overwritten. ```text Native Codex UI -> aenv gateway -> host Codex app-server -> model API | | | +-> sandbox exec-server +-> sandbox workspace service (/diff, files, processes) ``` ## Compatibility and operations - Public API, generated protocol, and storage formats: unchanged. - Client requirements: Linux, Git, and Codex 0.155.1. `start` and `resume` need an interactive terminal. Node.js is needed for npm installation of Codex. The template still includes Python for user project tasks; the integration does not depend on it. First-time template builds use the existing `aenv-buildctl` installed beside `aenv`. - Model configuration and authentication: managed by Codex under `~/.codex` or `CODEX_HOME`, including its configured credential store and provider environment variables. `aenv` stores only the template name in `~/.config/aenv/codex.json`; it neither prompts for nor copies model credentials. `--model` remains a temporary native Codex override. Sessions default to `~/.local/share/aenv/codex/sessions/`; XDG directories are honored. Resume with the same Codex home. - Upgrade/rollback: install the updated aenv binary; no server migration. Local and guest Codex versions must match the pinned version's experimental app-server protocol. - Interactive exit retains a paused sandbox and local saves. Run `finish` when done. Lease expiry auto-pauses a sandbox after abrupt launcher termination. ## Validation ```text cargo fmt -p aenv -- --check cargo clippy --locked --release -p aenv --all-targets -- -D warnings cargo test --locked --release -p aenv --bin aenv # 109 passed git diff --check ``` The checks above were run as a non-root user on the existing Linux test host for the deletion-recovery fix. Four new regression tests cover failed DELETE retries (including authorization errors), a lost DELETE response, a failed post-delete manifest write, and refusing deletion when the pending state cannot be persisted. They use local mock HTTP endpoints; the live sandbox/model workflow was not rerun for this fix. Earlier live checks on a Linux AgentENV deployment, running the compiled binary outside the source tree. The previous cleanup validation rechecked cleanup, export failure, and recovery; the other feature checks below preceded that cleanup change: - Built a new template from the embedded Dockerfile; reused an existing template. - Repeated the complete native workflow in a test template with neither `python` nor `python3` installed: read a random value present only inside the sandbox, edit files, inspect `/diff`, exit with saved files, and resume the same conversation for another edit. - `finish` saved results and deleted the sandbox. - An unsafe export was rejected without deleting the sandbox; `finish` recovered the work after the export issue was corrected. - Rechecked native start/resume, `/diff`, and failed-export recovery. Recovery works without model credentials, and repeated `finish` is safe. Non-terminal start/resume is rejected before creating or connecting a sandbox. - Latest cleanup validation used a template with neither `python` nor `python3`: an envd-tagged supervisor without a persisted record was recovered, TERM-ignoring descendants were stopped, and a stale record naming an unrelated group left that group running. An unsafe export retained the sandbox; correcting the export allowed `finish` to save and delete it. - Forcibly killing a supervisor caused cleanup to refuse numeric-PID fallback, preserve its remaining children, and pause the sandbox before saving. Both disposable validation sandboxes were confirmed deleted. - Linux regression tests exercise real supervisor TERM/KILL escalation and orphan cleanup after the service exits, preserving an unrelated process. A mock envd test replaces a dead service with another service at the same numeric PID and verifies that cleanup uses only the original unique tag. - Original project files remained unchanged. Disposable validation sandboxes were confirmed deleted. - Unit tests cover command parsing, template-only settings, conflicting execution configuration, private files and locking, Git file selection, literal filenames (including newlines, leading dashes, and non-UTF-8 names), hard links, archive traversal and symlink chains, stale process records, workspace RPC routing, helper-thread filtering, conversation ID recovery and write failures, and relay authentication/header isolation with binary frames. - Native Codex file-based API authentication (`codex login --with-api-key`) and custom provider `env_key` authentication both completed interactive sandbox tasks, `/diff`, saving and resume. Two overlapping sessions reused one native Codex home with separate sandbox files and conversations. Setup worked without any model configuration or credentials. Provider settings were preserved; native Codex recorded its own project trust setting. - With custom developer instructions and `tui.alternate_screen = "always"`, the model followed the configured instructions and the native UI entered and restored the alternate screen. Sandbox-only file access, `/diff`, saving, resume with a follow-up task, and `finish` all passed. Start/resume help no longer exposes a wrapper turn timeout. - Setup succeeded with a nonexistent local Codex executable and home. Resume used the standalone `thread-id` despite a stale legacy ID in `session.json`, and unchanged IDs retained the same file inode across resume and follow-up turns. Killing the owned launcher process group with SIGKILL still allowed the same sandbox and conversation to resume; `finish` then saved and deleted the test sandbox. - An existing `environments.toml` was rejected before a sandbox or session was created. Template setup discarded legacy model fields without migrating credentials. - Updated documentation links and command examples checked. Full mdBook rendering was not rerun; mdBook is unavailable in this build environment. Server, storage, and Go suites were skipped because those components are unchanged. ## Risks and reviewer notes Codex 0.155.1 prioritizes `environments.toml` over the per-process sandbox URL. The launcher rejects that configuration without changing the file; users can configure a separate native Codex home. Earlier draft model fields are ignored and removed on the next `setup`. Conversation history in an earlier draft's private session home is not automatically migrated: `finish` can save that project, then `start` opens it under native Codex configuration. Codex 0.155.1's native `@` picker searches the CLI machine even in remote mode. The guide tells users to type relative sandbox paths instead; model file access and native `/diff` work against the sandbox. Shutdown requires the service supervisor to remain available. Services from earlier drafts without supervisors, or services whose supervisors were externally killed, are retained for manual cleanup if live group members remain. The CLI refuses unsafe PID-based fallback. This uses the existing Bash/envd facilities and works with the default Linux 6.1 guest; no template rebuild or new runtime dependency is required. Model commands run with automatic approval inside the sandbox. Review `commands/codex/runtime.rs` for lifecycle and recovery, `guest.rs` for sandbox process ownership and cleanup, `socket.rs` for RPC boundaries, and `project.rs` for file transfer checks. ## Checklist - [x] One coherent change with no unrelated refactoring. - [x] New behavior covered by unit tests and live sandbox validation. - [x] No credentials or private infrastructure details in logs or examples committed here. - [x] No generated code manually modified. - [x] User documentation updated. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-29 14:22:20 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/AgentENV#336
No description provided.