Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 18 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@ jobs:
timeout-minutes: 240
steps:
- uses: actions/checkout@v7.0.1
- name: Reserve native build space
run: |
# These preinstalled SDKs are unused by this job. All Rust build tools
# come from the pinned container, and Node/Terraform are installed below.
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
available=$(df -Pk . | awk 'NR == 2 {print $4}')
if [ "$available" -lt 20971520 ]; then
echo "Native builds need 20 GiB free. Set RAT_NATIVE_RUNNER to an ARM64 runner with more disk."
exit 1
fi
- uses: actions/setup-node@v7.0.0
with:
node-version: 22
Expand All @@ -36,12 +26,10 @@ jobs:
id: codex-runtime
with:
path: .runtime/codex/linux-arm64
key: codex-linux-arm64-${{ hashFiles('runtime/codex/**', '!runtime/codex/model-capabilities.json', '!runtime/codex/README.md', 'scripts/build-codex-runtime.mjs', 'scripts/codex-runtime-targets.mjs') }}
- name: Build pinned Linux ARM64 runtime
key: official-codex-linux-arm64-${{ hashFiles('runtime/codex/source.json', 'runtime/codex/companion-packages.json', 'package-lock.json', 'scripts/build-codex-runtime.mjs', 'scripts/codex-runtime-artifact.mjs', 'scripts/codex-runtime-targets.mjs') }}
- name: Package official Linux ARM64 runtime
if: steps.codex-runtime.outputs.cache-hit != 'true'
run: docker buildx build --platform linux/arm64 --file runtime/codex/Dockerfile --output type=local,dest=.runtime/codex/linux-arm64 .
# Cache a completed compilation even if a later acceptance check fails.
# Restoring this cache never skips package, checksum or native image tests.
run: node scripts/build-codex-runtime.mjs .runtime/codex/linux-arm64
- uses: actions/cache/save@v4
if: steps.codex-runtime.outputs.cache-hit != 'true'
with:
Expand Down Expand Up @@ -85,31 +73,35 @@ jobs:
- run: npm ci
- name: Verify x86 sandbox enforcement with the pinned upstream runtime
run: npx vitest run tests/pi/managed-effects.test.ts tests/runner/managed-sandbox.test.ts tests/simulation/linux-kvm-helper.test.ts tests/simulation/native-vm-prototype.test.ts --no-file-parallelism
- name: Reserve native build space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
available=$(df -Pk . | awk 'NR == 2 {print $4}')
test "$available" -ge 20971520
- uses: actions/cache/restore@v4
id: codex-runtime
with:
path: .runtime/codex/linux-x64
key: codex-linux-x64-${{ hashFiles('runtime/codex/**', '!runtime/codex/model-capabilities.json', '!runtime/codex/README.md', 'scripts/build-codex-runtime.mjs', 'scripts/codex-runtime-targets.mjs') }}
- name: Build pinned Linux x64 runtime
key: official-codex-linux-x64-${{ hashFiles('runtime/codex/source.json', 'runtime/codex/companion-packages.json', 'package-lock.json', 'scripts/build-codex-runtime.mjs', 'scripts/codex-runtime-artifact.mjs', 'scripts/codex-runtime-targets.mjs') }}
- name: Package official Linux x64 runtime
if: steps.codex-runtime.outputs.cache-hit != 'true'
run: docker buildx build --platform linux/amd64 --file runtime/codex/Dockerfile --output type=local,dest=.runtime/codex/linux-x64 .
run: node scripts/build-codex-runtime.mjs .runtime/codex/linux-x64
- uses: actions/cache/save@v4
if: steps.codex-runtime.outputs.cache-hit != 'true'
with:
path: .runtime/codex/linux-x64
key: ${{ steps.codex-runtime.outputs.cache-primary-key }}
- name: Validate x64 artifact provenance
run: node --input-type=module -e "import { validateCodexRuntimeArtifact } from './scripts/codex-runtime-artifact.mjs'; await validateCodexRuntimeArtifact('.runtime/codex/linux-x64', { expectedTarget:'x86_64-unknown-linux-gnu' });"
- name: Verify patched x86 sandbox and local Pi transport
run: node --input-type=module -e "import { validateCodexRuntimeArtifact } from './scripts/codex-runtime-artifact.mjs'; await validateCodexRuntimeArtifact('.runtime/codex/linux-x64', { expectedTarget:'x86_64-unknown-linux-musl' });"
- name: Verify x64 native contracts, checkpoints and Pi sandbox
env:
CODEX_CONFORMANCE_BINARY: ${{ github.workspace }}/.runtime/codex/linux-x64/runtime/bin/codex
CODEX_REQUIRE_PARITY: 'true'
run: npx vitest run tests/pi/managed-effects.test.ts tests/pi/managed-subprocess.test.ts tests/runner/managed-sandbox.test.ts tests/agents/local-pi-transport.test.ts tests/agents/local-pi.test.ts --no-file-parallelism
run: |
npm run test:agents:parity:host
npx vitest run tests/runner/managed-sandbox.test.ts --no-file-parallelism
- name: Verify x64 isolated cold recovery
env:
CODEX_RUNTIME_ARTIFACT: ${{ github.workspace }}/.runtime/codex/linux-x64
run: |
npm run runtime:local:build
docker buildx build --platform linux/amd64 --load --file testing/native-parity.Dockerfile --build-arg WORKER_IMAGE=rat-things-local:1 --tag rat-things-native-parity:x64 .
docker run --rm --platform linux/amd64 --privileged --init --user 0 --env CODEX_COLD_NATIVE_E2E=true --entrypoint npx rat-things-native-parity:x64 --no-install vitest run tests/runner/codex-cold-verification.test.ts --no-file-parallelism
- name: Archive verified Linux x64 runtime
run: tar -C .runtime/codex/linux-x64 -czf .runtime/codex/linux-x64.tar.gz artifact.json runtime
- name: Export verified Linux x64 runtime
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ npm run test:e2e:localstack

Terraform requires packaged Lambda artifacts:

Packaging also requires the patched Linux ARM64 Codex artifact. Build it with
Packaging also requires the official, unmodified Linux ARM64 Codex artifact. Package it with
`runtime/codex/Dockerfile` or select an exported artifact with
`CODEX_RUNTIME_ARTIFACT`; see `testing/README.md`. `npm run check` includes packaging
and validates this artifact. CI caches it by source, patch and builder identity.
and validates this artifact. CI caches it by official package and packager identity.

```bash
npm run package
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ npm run console:serve
```

For the full repository checks, run `npm run check`. It includes Lambda packaging
and requires a patched Linux ARM64 Codex artifact, Docker and Terraform; see
and requires an official Linux ARM64 Codex artifact, Docker and Terraform; see
[development prerequisites](testing/README.md). To deploy a backend, start with
the [AWS quickstart](docs/quickstart.md).

Expand Down
8 changes: 4 additions & 4 deletions desktop/tests/local_pi_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ fn saved_pi_agent_runs_managed_tools_and_restores_in_rust_console() {
&mut app,
"Task",
&format!(
"Perform this exact managed workspace verification using all four tools: (1) write_file path {file} with content {first}; (2) read_file that path and confirm its exact content; (3) list_files /workspace and locate that file; (4) exec_command with command array [\"node\",\"-e\",\"console.log('RUST_UI_WORKER '+process.getuid()+' '+process.platform)\"] and confirm it prints RUST_UI_WORKER 10001 linux. Then respond with exactly {first}."
"Perform this exact managed workspace verification using all four tools: (1) write_file path {file} with content {first}; (2) read_file that path and confirm its exact content; (3) list_files /workspace and locate that file; (4) exec_command with command array [\"node\",\"--disable-warning=UNDICI-EHPA\",\"-e\",\"console.log('RUST_UI_WORKER '+process.getuid()+' '+process.platform)\"] and confirm it prints RUST_UI_WORKER 10001 linux. Then respond with exactly {first}."
),
);
capture(&mut app, &evidence, "managed-session-form.png");
Expand Down Expand Up @@ -471,7 +471,7 @@ fn saved_pi_agent_runs_managed_tools_and_restores_in_rust_console() {
});
let guest_command = require_operation(
&first_commands,
&json!({"command":["node","-e","console.log('RUST_UI_WORKER '+process.getuid()+' '+process.platform)"]}),
&json!({"command":["node","--disable-warning=UNDICI-EHPA","-e","console.log('RUST_UI_WORKER '+process.getuid()+' '+process.platform)"]}),
|text| text.trim() == "RUST_UI_WORKER 10001 linux",
);
show_command(&mut app, guest_command);
Expand Down Expand Up @@ -499,7 +499,7 @@ fn saved_pi_agent_runs_managed_tools_and_restores_in_rust_console() {
&mut app,
"Message",
&format!(
"Continue this same Session. Use read_file on {file} to confirm the existing content is {first}. Then use write_file to replace its content with exactly {second}, use read_file again to verify it, and use exec_command with command array [\"node\",\"-e\",\"console.log('RUST_UI_CONTINUED '+process.getuid())\"]. Respond with exactly {second}."
"Continue this same Session. Use read_file on {file} to confirm the existing content is {first}. Then use write_file to replace its content with exactly {second}, use read_file again to verify it, and use exec_command with command array [\"node\",\"--disable-warning=UNDICI-EHPA\",\"-e\",\"console.log('RUST_UI_CONTINUED '+process.getuid())\"]. Respond with exactly {second}."
),
);
click(&mut app, "Send");
Expand Down Expand Up @@ -541,7 +541,7 @@ fn saved_pi_agent_runs_managed_tools_and_restores_in_rust_console() {
});
let continued_command = require_operation(
&continued_commands,
&json!({"command":["node","-e","console.log('RUST_UI_CONTINUED '+process.getuid())"]}),
&json!({"command":["node","--disable-warning=UNDICI-EHPA","-e","console.log('RUST_UI_CONTINUED '+process.getuid())"]}),
|text| text.trim() == "RUST_UI_CONTINUED 10001",
);
show_command(&mut app, continued_command);
Expand Down
23 changes: 23 additions & 0 deletions docs/agents-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ for await (const event of await client.beta.agents.sessions.events.stream(sessio

SSE is a live stream. Recover missed work from saved Items and Turns; reconnecting
does not replay an event log. Disconnecting a stream does not cancel execution.

Command-output deltas arrive once the command finishes, immediately before its
completed Item. This keeps their text in the order reported by the native
executor's completed aggregate, including its output limit and any omission
marker. Assistant text and reasoning summaries continue to stream as they arrive.
Function tool results must identify the pending call and Turn. Successful results
provide `output`; failed results provide `error`. Human approval requests are not
part of the runtime: the deployment admits a fixed capability envelope before
Expand Down Expand Up @@ -397,6 +402,24 @@ retains flushed workspace files and setup identity after confirmed termination o
worker. Neither runtime restores running processes. Checkpointing is host-controlled; there
is no public checkpoint endpoint or automatic idle timer.

Codex checkpoints require successful completed Turns. Before publication, the
host stops native writers, flushes the Session journal, synchronizes storage and
opens a disposable copy with the official Codex binary. Root and child thread
identities and complete public native history must survive a fresh-process
resume. Verification has no network or credentials and cannot run model work or
tools. Extra coordination details omitted by Codex's public history remain in
the host journal. This does not verify Codex's hidden mailbox state.

Codex cold checkpoints currently support the built-in OpenAI provider and custom
Responses API providers. Bedrock, Ollama and LM Studio are refused before the
running process stops because their cold recovery has not been validated. This
restriction does not prevent ordinary Sessions or Pi Durable execution.

Checkpointing refuses unsupported startup integrations, external native storage,
failed or interrupted native history, and unverifiable saved state. An ordinary
process exit alone cannot publish a checkpoint. These limits also apply when
forking requires a new Codex checkpoint.

## Fork a Session

Set `session_checkpoints_enabled = true` with S3 Files configured to enable forks;
Expand Down
4 changes: 2 additions & 2 deletions docs/development-and-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public sharing. Return here when choosing a longer-lived installation shape.
## Prerequisites

- Node.js 22.20+, npm, and Git.
- Docker with Compose for LocalStack and Buildx for the patched Linux ARM64 runtime and image canaries.
- A verified patched native artifact for packaging; build or import it using
- Docker with Compose for LocalStack and Buildx for the official Linux ARM64 runtime and image canaries.
- A verified official native artifact for packaging; build or import it using
[`testing/README.md`](../testing/README.md#agents-api-native-compatibility-gate).
- Terraform 1.16.6, matching `.terraform-version`, CI and the LocalStack container,
and AWS credentials for infrastructure work. The module requires Terraform 1.9+
Expand Down
2 changes: 1 addition & 1 deletion docs/local-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ active worker. Conversations with **No environment** do not require a VM.
Windows and Linux with Docker Desktop, Intel Macs, and native Linux Docker with the
gVisor `runsc` runtime are in preview. Set `RAT_THINGS_PREVIEW_PLATFORMS=1` to try
them. Native Linux Docker without gVisor is refused, because the worker would share
the host kernel. A source checkout can build the patched Linux x86-64 worker.
the host kernel. A source checkout can package the official Codex release into the Linux x86-64 worker.
The [KVM development setup](../testing/local-runtime/linux-kvm/README.md) uses a
dedicated VM on Linux x86-64 when `/dev/kvm` and vsock are available. It requires
an explicit asset path and is separate from the signed macOS installer. A gVisor
Expand Down
2 changes: 1 addition & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Use the [deployment guide](development-and-deployment.md) to configure the Terra
module, model credentials, ARM64 runtime image and Agents HTTP service. Package
Lambda artifacts before Terraform validation or deployment. Deployment creates
AWS resources; ordinary local checks do not provision MicroVMs. Packaging requires the
patched Linux ARM64 Codex artifact described in the [contributor guide](../testing/README.md#agents-api-native-compatibility-gate). Do not substitute the stock npm binary.
official Linux ARM64 Codex artifact described in the [contributor guide](../testing/README.md#agents-api-native-compatibility-gate). Keep its verified manifest and complete companion files together.

## Automated setup

Expand Down
16 changes: 15 additions & 1 deletion docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ execution boundary. Trusted orchestration runs as root and launches Codex or Pi
as UID/GID 10001. The worker sandbox defaults to workspace-only writes with agent networking off.
The host-side local harness retains its separate read-only/no-network policy.

Managed execution verifies the official Codex process's effective permission
profile before exposing tools. Unexpected merged grants, unknown policy files or
incomplete policy inspection prevent startup. Agent networking off uses a network
namespace and a proxy with no allowed destinations. Local socket metadata and
anonymous socketpairs remain available for subprocess I/O; external connections
and named Unix socket access remain denied.

The EC2 worker supports connected Session lifetime beyond Lambda MicroVM's maximum lifetime.
Both backends must preserve the same ownership, process and credential boundaries. Self-hosted
executor connections also require an operator-controlled sandbox; transport encryption does
Expand Down Expand Up @@ -91,7 +98,7 @@ from actor attribution. No caller-provided URL or credential may establish owner
| Superseded worker write | Immutable execution generation, backend identity and conditional state changes | Lost process memory cannot be recreated from public Items alone |
| Artifact disclosure | Private encrypted objects, owner checks, saved Turn/path identity and explicit publication grants | Publication URLs are bearer credentials; provider copies have independent retention |
| Resource exhaustion | Bounded requests, pagination, queues and deployment concurrency controls | Configure tenant budgets, API throttles and provider-event abuse limits |
| Supply-chain compromise | Locked packages, pinned source/base image, recorded patches and artifact digests | Review build provenance and scan/sign release artifacts |
| Supply-chain compromise | Locked packages, pinned source/base image, official package integrity and complete artifact digests | Review build provenance and scan/sign release artifacts |

## Fixed capability-envelope security model

Expand Down Expand Up @@ -201,6 +208,13 @@ the same owner/Session storage under its fenced execution identity. Native check
harness history; public-item recovery preserves historical facts without replaying tool effects.
Neither recovery path promises survival of a process whose VM has been destroyed.

Codex checkpoint publication requires a successful cold resume of copied native
history after all writers stop and storage is synchronized. A separate verifier
runs without credentials or network access; it cannot modify the saved candidate.
Evidence covers root and child identities, public native history, and the flushed
host journal. It does not inspect hidden Codex mailbox state or preserve running
commands. Unsupported startup integrations or unverifiable state prevent handoff.

The EC2 supervisor requires the outer dedicated VM for its privileged mount/network setup. The
agent does not receive the Docker socket or host control configuration. Metadata and the local
control listener are denied to the guest while trusted root orchestration remains able to operate.
Expand Down
5 changes: 3 additions & 2 deletions docs/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ published release cadence. Operators apply updates through the existing
[local runtime setup](local-workspace.md#give-your-session-a-linux-workspace).

An update should identify the reviewed repository revision and the matching
complete runtime artifacts for the target platform. Codex source, ordered patches,
companion packages and file inventories are pinned together. Keep the artifact
complete runtime artifacts for the target platform. The official Codex release,
companion packages and file inventories are pinned together; Rat Things does not
patch the Codex executable. Keep the artifact
manifest with its runtime directory; replacing only the Codex executable with an
unrelated upstream release is not a supported upgrade. Artifact verification
checks identity and file integrity; it does not establish a signature or prove
Expand Down
6 changes: 3 additions & 3 deletions microvm/runtime-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,9 @@ function startRun(run) {
storagePreparationDurationMs = Date.now() - preparationStartedAt;
run.environment.SESSION_STATE_ROOT = stateRoot;
run.environment.CODEX_HOME = join(stateRoot, 'codex-home');
// SQLite WAL/connection locks stay on this worker's local filesystem.
// Native rollouts remain durable in CODEX_HOME and rebuild the indexes
// when a replacement worker resumes the saved thread.
// Ordinary runs bind this directory to worker-local storage. Checkpoint
// mode retains the databases and WAL beside the native home; paginated
// history cannot be reconstructed from legacy rollout files alone.
run.environment.CODEX_SQLITE_HOME = join(stateRoot, 'codex-home', 'sqlite');
run.environment.BROWSER_PROFILE_ROOT = join(stateRoot, 'codex-home', 'browser-profile');
run.environment.WORKSPACE_ROOT = stateRoot;
Expand Down
Loading
Loading